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 Gates | 0 | 0 |
Steve Jobs | 0 | 0 |
Ada Lovelace | 0 | 0 |
Alan Turing | 0 | 0 |
Active Tasks
Owner Name | Description |
---|
Completed Tasks
Owner Name | Description |
---|
CREATE TYPES FOR OUR STORE
Start by creating a file for your store (e.g., store.ts) and adding the following types:
store.tstype TaskOwner = {
ownerID: number;
firstName: string;
lastName: string;
};
export type Task = {
ownerID: number;
description: string;
};
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 timesstore.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.tsimport { 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>
)
}
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>
)
}
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>
)
}