Example

In this example, we will build a basic TODO app to highlight setting up your store in Trigger. The final product is shown below. Click the green icon to complete a task and the red icon to activate a task.

Owners
Owner Name# Active Tasks# Completed Tasks
Bill Gates00
Steve Jobs00
Ada Lovelace00
Alan Turing00
Active Tasks
Owner NameDescription
Completed Tasks
Owner NameDescription

CREATE TYPES FOR OUR STORE

Start by creating a file for your store (e.g., store.ts) and adding the following types:

store.ts
type TaskOwner = {
    ownerID: number;
    firstName: string;
    lastName: string;
};

export type Task = {
    ownerID: number;
    description: string;
};
Note: You can name your store file whatever you like, and you can have as many stores as you want to provide better localization of data in your application

INSTANTIATE OUR STORE

With our types declared, we now instantitate our store and export it for use throughout our application. You can do this in the same file where you declared your types. Start by importing the CreateSingle, CreateTable and CreateStore convenience functions from the library.

Note: We are using a single called initialLoad to ensure we don't load data into our store multiple times
store.ts
import { CreateSingle, CreateTable, CreateStore } from '@datahook/trigger';

export const store = CreateStore({
    taskOwners: CreateTable<TaskOwner>({ ownerID: [1, 2, 3, 4], firstName: ['Bill', 'Steve', 'Ada', 'Alan'], lastName: ['Gates', 'Jobs', 'Lovelace', 'Turing'] }),
    activeTasks: CreateTable<Task>(['ownerID', 'description']),
    completedTasks: CreateTable<Task>(['ownerID', 'description']),
    initialLoad: CreateSingle(true),
});

The final version of our store is shown below, and is now ready for use in our application.

store.ts
import { CreateSingle, CreateTable, CreateStore } from '@datahook/trigger';
export type { TableRow } from '@datahook/trigger';

type TaskOwner = {
    ownerId: number;
    firstName: string;
    lastName: string;
};

export type Task = {
    ownerId: number;
    description: string;
};

export const store = CreateStore({
    taskOwners: CreateTable<TaskOwner>({ ownerID: [1, 2, 3, 4], firstName: ['Bill', 'Steve', 'Ada', 'Alan'], lastName: ['Gates', 'Jobs', 'Lovelace', 'Turing'] }),
    activeTasks: CreateTable<Task>(['ownerID', 'description']),
    completedTasks: CreateTable<Task>(['ownerID', 'description']),
    initialLoad: CreateSingle(true),
});

CREATE OUR COMPONENTS

Note: For brevity, not all imports are shown (e.g., React, styling, etc.)
app.tsx
import { store } from './store';
import TaskOwners from './taskOwners';
import ActiveTasks from './activeTasks';
import CompletedTasks from './completedTasks';

export default function App() {
    const initialLoad = store.initialLoad.get();
    useLayoutEffect(() => {
        if (initialLoad) {
            store.initialLoad.set(false);
            store.activeTasks.insertMany([
                {
                    ownerId: 1,
                    description: 'Invent Internet Explorer',
                },
                {
                    ownerId: 2,
                    description: 'Invent iPhone',
                },
                {
                    ownerId: 3,
                    description: 'Invent programming',
                },
                {
                    ownerId: 4,
                    description: 'Invent intelligent machines',
                },
            ]);
        }
    }, []);

    return (
        <div className={app}>
            <TaskOwners />
            <ActiveTasks />
            <CompletedTasks />
        </div>
    )
}
taskOwners.tsx
import { store } from './store';

// Will show how may active and completed tasks for each owner
export default function TaskOwners() {
    const activeTasks = store.activeTasks.use(null, ['onDelete', 'onInsert']);
    const completedTasks = store.completedTasks.use(null, ['onDelete', 'onInsert']);
    const owners = store.taskOwners.use();

    return (
        <div className={table}>
            <div className={tableHeader}>Owners</div>
            <div className={tableContainer}>
                <table className={tableBody}>
                    <thead>
                        <tr>
                            <th>Owner Name</th>
                            <th># Active Tasks</th>
                            <th># Completed Tasks</th>
                        </tr>
                    </thead>
                    <tbody>
                        {owners.map(o =>
                            <tr key={o._id}>
                                <td>{o.firstName} {o.lastName}</td>
                                <td>{activeTasks.filter(d => d.ownerID === o.ownerID).length}</td>
                                <td>{completedTasks.filter(d => d.ownerID === o.ownerID).length}</td>
                            </tr>
                        )}
                    </tbody>
                </table>
            </div>
        </div>
    )
}
tasks.tsx
import { store, type Task, type TableRow } from './store';

// Will show the active tasks
function ActiveTasks() {
    const tasks = store.activeTasks.use();

    const handleCompleteTask = (_id: number) => {
        const task = store.activeTasks.findById(_id);
        if (task) {
            store.activeTasks.deleteById(_id);
            store.completedTasks.insertOne({ ownerId: task.ownerId, description: task.description });
        }
    }
    return <TaskTable tasks={tasks} tooltip="Click to complete task" iconColour="success" title="Active Tasks" handleToggleTask={handleCompleteTask} />
}

// Will show the completed tasks
function CompletedTasks() {
    const tasks = store.completedTasks.use();

    const handleActivateTask = (_id: number) => {
        const task = store.completedTasks.findById(_id);
        if (task) {
            store.completedTasks.deleteById(_id);
            store.activeTasks.insertOne({ ownerId: task.ownerId, description: task.description });
        }
    }
    return <TaskTable tasks={tasks} tooltip="Click to activate task" iconColour="error" title="Completed Tasks" handleToggleTask={handleActivateTask} />
}

type Props = {
    tasks: TableRow<Task>[];
    tooltip: string;
    title: string;
    iconColour: 'success' | 'error';
    handleToggleTask(n: number): void;
}

function TaskTable({ tasks, tooltip, iconColour, title, handleToggleTask }: Props) {
    return (
        <div className={table}>
            <div className={tableHeader}>{title}</div>
            <div className={tableContainer}>
                <table className={tableBody}>
                    <thead>
                        <tr>
                            <th>Owner Name</th>
                            <th>Description</th>
                            <th></th>
                        </tr>
                    </thead>
                    <tbody>
                        {tasks.map(t =>
                            <tr key={t._id}>
                                <td>{store.taskOwners.findOne({ ownerId: t.ownerId})!.firstName} {store.taskOwners.findOne({ ownerId: t.ownerId})!.lastName}</td>
                                <td>{t.description}</td>
                                <td className={icon} title={tooltip} onClick={() => handleToggleTask(t._id)}>
                                    {iconColour === 'success' 
                                        ? <CheckCircle color={iconColour} fontSize="large"/>
                                        : <Cancel color={iconColour} fontSize="large" />
                                    }
                                    </td>
                            </tr>
                        )}
                    </tbody>
                </table>
            </div>
        </div>
    )
}
Built with in Halifax, Nova Scotia by JW