0.1.0 • Published 4 months ago
@domeadev/react-store-context v0.1.0
React Store Context
A simple and lightweight store context for React built on top of Zustand.
Installation
npm
npm install @domeadev/react-store-context
yarn
yarn add @domeadev/react-store-context
pnpm
pnpm add @domeadev/react-store-context
Features
- 🪶 Lightweight wrapper around Zustand
- 🧩 Context-based state sharing
- 🔄 Component subscription with minimal re-renders
- 🎯 Type-safe selectors
- 🌳 Tree-shakeable exports
Usage
Basic Example
import {
createDefaultStore,
createStoreContext,
} from "@domeadev/react-store-context";
import React from "react";
// Define todo type
interface Todo {
id: string;
text: string;
completed: boolean;
}
// Create a store creator function
const createTodosStore = () =>
createDefaultStore(
// initial state
{ todos: [] as Todo[] },
(set) => ({
addTodo: (text: string) =>
set((state) => ({
todos: [
...state.todos,
{ id: Math.random().toString(36).slice(2, 9), text, completed: false },
],
})),
toggleTodo: (id: string) =>
set((state) => ({
todos: state.todos.map((todo) =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
),
})),
removeTodo: (id: string) =>
set((state) => ({
todos: state.todos.filter((todo) => todo.id !== id),
})),
})
);
// Create the store context
const { StoreProvider, useStore, Subscribe, createStoreSelector } =
createStoreContext(createTodosStore);
// Use selectors for type safety
const selectTodos = createStoreSelector((state) => state.todos);
const selectActions = createStoreSelector((state) => ({
addTodo: state.addTodo,
toggleTodo: state.toggleTodo,
removeTodo: state.removeTodo,
}));
// TodoList component
const TodoList = () => {
const todos = useStore(selectTodos);
const { toggleTodo, removeTodo } = useStore(selectActions);
return (
<ul>
{todos.map((todo) => (
<li key={todo.id} style={{ textDecoration: todo.completed ? "line-through" : "none" }}>
<input
type="checkbox"
checked={todo.completed}
onChange={() => toggleTodo(todo.id)}
/>
{todo.text}
<button onClick={() => removeTodo(todo.id)}>Delete</button>
</li>
))}
</ul>
);
};
// App component
const App = () => {
return (
<StoreProvider>
<TodoList />
{/* Other components that need access to the todos state */}
</StoreProvider>
);
};
Using the Subscribe Component
You can use the Subscribe
component for declarative subscriptions:
const TodoCounter = () => {
return (
<Subscribe selector={selectTodos}>
{(todos) => (
<div>
Total: {todos.length} | Completed: {todos.filter(todo => todo.completed).length}
</div>
)}
</Subscribe>
);
};
Passing Initial Props
You can pass initial props to your store:
interface TodoStoreProps {
initialTodos?: Todo[];
}
const { StoreProvider } = createStoreContext((props?: TodoStoreProps) =>
createDefaultStore(
{ todos: props?.initialTodos || [] },
(set) => ({
addTodo: (text: string) =>
set((state) => ({
todos: [
...state.todos,
{ id: Math.random().toString(36).slice(2, 9), text, completed: false },
],
})),
toggleTodo: (id: string) =>
set((state) => ({
todos: state.todos.map((todo) =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
),
})),
removeTodo: (id: string) =>
set((state) => ({
todos: state.todos.filter((todo) => todo.id !== id),
})),
})
)
);
// Usage
<StoreProvider initialTodos={[
{ id: '1', text: 'Learn React', completed: true },
{ id: '2', text: 'Learn TypeScript', completed: false },
]}>
<TodoList />
</StoreProvider>;
API Reference
createStoreContext(storeCreator)
Creates a React context for your store.
Parameters:
storeCreator
: A function that creates a store instance
Returns:
StoreContext
: The React context objectStoreProvider
: A provider component for the storeuseStore
: A hook to access the store statecreateStoreSelector
: A utility to create typed selectorsSubscribe
: A component for declarative subscriptions
createDefaultStore(initialState, actionsCreator)
Creates a default store with initial state and actions.
Parameters:
initialState
: The initial state objectactionsCreator
: A function that returns actions using Zustand'sset
function
License
MIT © domeafavour