Skip to content

Getting Started with Bindra

Welcome to Bindra! This guide will help you get up and running with Bindra in your application.

Table of Contents


Installation

Install Bindra using your preferred package manager:

bash
# npm
npm install bindra

# pnpm
pnpm add bindra

# yarn
yarn add bindra

TypeScript Support

Bindra is written in TypeScript and provides full type safety out of the box. No additional @types packages needed!

typescript
import { DataSource, type DataSourceConfig } from 'bindra';

Core Concepts

DataSource

The DataSource is the heart of Bindra. It manages your data and provides:

  • Reactivity: Automatic UI updates when data changes
  • CRUD Operations: Create, Read, Update, Delete
  • Navigation: Move through records (next, prev, goto)
  • Dual Mode: Works with local arrays or remote APIs

Reactivity

Bindra uses signals and reactive objects to track changes:

typescript
// Signals - simple reactive values
const count = createSignal(0);
count.subscribe(value => console.log(value));
count.set(1); // Console: 1

// Reactive Objects - deep reactivity
const user = reactive({ name: 'Alice', age: 25 });

Local vs Remote

Bindra works seamlessly with both local data and remote APIs:

  • Local: Fast, synchronous operations with arrays
  • Remote: Automatic HTTP requests with caching and retry

Your First DataSource

Working with Local Data

Let's create a simple to-do list:

typescript
import { DataSource } from 'bindra';

interface Todo {
  id: number;
  title: string;
  completed: boolean;
}

// Initialize with local data
const todos = new DataSource<Todo>({
  data: [
    { id: 1, title: 'Learn Bindra', completed: false },
    { id: 2, title: 'Build an app', completed: false },
    { id: 3, title: 'Ship to production', completed: false }
  ]
});

// Subscribe to changes
todos.currentRecord.subscribe((todo: Todo | null) => {
  console.log('Current todo:', todo);
});

// Navigate
todos.next();  // Move to next todo
todos.prev();  // Move to previous todo
todos.goto(0); // Jump to first todo

Working with Remote APIs

Connect to a REST API:

typescript
interface User {
  id: number;
  name: string;
  email: string;
}

// Remote DataSource
const users = new DataSource<User>({
  url: 'https://api.example.com/users'
});

// Fetch data
await users.fetch();

// Data is now reactive
users.data; // User[] | null
users.currentRecord.value; // Current user

Basic Operations

Create (POST)

typescript
// Create a new record
const newUser = await users.create({
  name: 'Alice',
  email: 'alice@example.com'
});

console.log(newUser); // { id: 4, name: 'Alice', email: 'alice@example.com' }

Read (GET)

typescript
// Fetch all records
await users.fetch();

// Fetch with query
await users.fetch({
  filter: { active: true },
  sort: { field: 'name', order: 'asc' },
  limit: 10
});

// Get current record
const current = users.currentRecord.value;

Update (PUT/PATCH)

typescript
// Update a record
const updated = await users.update(1, {
  name: 'Alice Smith'
});

console.log(updated); // { id: 1, name: 'Alice Smith', ... }

Delete (DELETE)

typescript
// Delete a record
await users.delete(1);

// Record is removed from data array
console.log(users.data); // No longer contains id: 1

Working with Reactivity

Subscribe to Changes

typescript
// Subscribe to current record
const unsubscribe = users.currentRecord.subscribe((user) => {
  console.log('User changed:', user);
});

// Subscribe to data array
users.data$.subscribe((data) => {
  console.log('Data changed:', data);
});

// Subscribe to loading state
users.loading$.subscribe((loading) => {
  console.log('Loading:', loading);
});

// Cleanup
unsubscribe();

Using with UI Frameworks

React

typescript
import { useEffect, useState } from 'react';

function UserList() {
  const [users, setUsers] = useState<User[]>([]);
  
  useEffect(() => {
    const ds = new DataSource<User>({
      url: '/api/users'
    });
    
    // Subscribe to data changes
    const unsubscribe = ds.data$.subscribe(setUsers);
    
    // Fetch initial data
    ds.fetch();
    
    // Cleanup
    return () => unsubscribe();
  }, []);
  
  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

Vue 3

vue
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';
import { DataSource } from 'bindra';

interface User {
  id: number;
  name: string;
}

const users = ref<User[]>([]);
const ds = new DataSource<User>({ url: '/api/users' });

let unsubscribe: (() => void) | null = null;

onMounted(() => {
  unsubscribe = ds.data$.subscribe(data => {
    users.value = data || [];
  });
  ds.fetch();
});

onUnmounted(() => {
  unsubscribe?.();
});
</script>

<template>
  <ul>
    <li v-for="user in users" :key="user.id">
      {{ user.name }}
    </li>
  </ul>
</template>

Navigate through records easily:

typescript
const users = new DataSource<User>({
  data: [/* ... */]
});

// Navigation methods
users.next();      // Move to next record
users.prev();      // Move to previous record
users.first();     // Jump to first record
users.last();      // Jump to last record
users.goto(5);     // Jump to specific index

// Current state
console.log(users.currentIndex.value);  // Current index
console.log(users.currentRecord.value); // Current record
console.log(users.isFirst);             // At first record?
console.log(users.isLast);              // At last record?

Events

Listen to lifecycle events:

typescript
const users = new DataSource<User>({ url: '/api/users' });

// Before/after events
users.on('beforeFetch', () => console.log('Fetching...'));
users.on('afterFetch', (data) => console.log('Fetched:', data));

users.on('beforeCreate', (record) => console.log('Creating:', record));
users.on('afterCreate', (record) => console.log('Created:', record));

users.on('beforeUpdate', ({ id, changes }) => console.log('Updating:', id));
users.on('afterUpdate', (record) => console.log('Updated:', record));

users.on('beforeDelete', (id) => console.log('Deleting:', id));
users.on('afterDelete', (id) => console.log('Deleted:', id));

// Error events
users.on('error', (error) => console.error('Error:', error));

Middleware

Transform data with middleware:

typescript
// Add timestamp to all created records
users.middleware.add('beforeCreate', async (record, next) => {
  record.createdAt = new Date().toISOString();
  return next(record);
});

// Log all operations
users.middleware.add('afterFetch', async (data, next) => {
  console.log(`Fetched ${data.length} records`);
  return next(data);
});

// Validate before create
users.middleware.add('beforeCreate', async (record, next) => {
  if (!record.email?.includes('@')) {
    throw new Error('Invalid email');
  }
  return next(record);
});

Next Steps

Now that you understand the basics, explore advanced features:

Learn More

Advanced Features

  1. Validation - Data validation system
  2. Caching - TTL-based caching
  3. Pagination - Offset & cursor pagination
  4. Real-time - WebSocket integration
  5. Batch Operations - Bulk CRUD
  6. Optimistic Updates - Instant UI feedback

Examples to Try

  1. Basic CRUD - Build a simple CRUD app
  2. Real-time Collaboration - WebSocket chat
  3. Pagination - Infinite scroll

Need Help?


Happy coding with Bindra! 🚀

Released under the MIT License.