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 bindraTypeScript 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 todoWorking 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 userBasic 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: 1Working 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>Navigation
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
- API Reference - Complete DataSource API
- Examples - Real-world examples
- Migration Guide - Upgrading from v1.x
Advanced Features
- Validation - Data validation system
- Caching - TTL-based caching
- Pagination - Offset & cursor pagination
- Real-time - WebSocket integration
- Batch Operations - Bulk CRUD
- Optimistic Updates - Instant UI feedback
Examples to Try
- Basic CRUD - Build a simple CRUD app
- Real-time Collaboration - WebSocket chat
- Pagination - Infinite scroll
Need Help?
- GitHub Issues - Report bugs or request features
- GitHub Discussions - Ask questions
- Examples - Browse working examples
Happy coding with Bindra! 🚀