0.1.0 โข Published 9 months ago
@developedbyed/superstate v0.1.0
Superstate
A lightweight, framework-agnostic state management library inspired by Zustand.
Features
- ๐ฆ Simple API: Minimalist API that's easy to learn
- ๐ Immutable updates: State is updated immutably
- ๐งช TypeScript-first: Built with TypeScript for excellent type inference
- ๐งฉ Middleware support: Extend functionality with middleware
- ๐ Selective subscriptions: Subscribe to specific parts of your state
- ๐ Framework agnostic: Use with any framework or vanilla JavaScript
Installation
npm install @developedbyed/superstateQuick Start
import { createStore } from "@developedbyed/superstate";
// Create a store
const useCounterStore = createStore((set, get) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
reset: () => set({ count: 0 }),
}));
// Use the store
console.log(useCounterStore.getState().count); // 0
// Update the state
useCounterStore.getState().increment();
console.log(useCounterStore.getState().count); // 1
// Subscribe to state changes
const unsubscribe = useCounterStore.subscribe((state) =>
console.log("State changed:", state)
);
// Later: unsubscribe when no longer needed
unsubscribe();Middleware
Enhance your store with middleware:
import {
createStore,
applyMiddleware,
logger,
persist,
} from "@developedbyed/superstate";
const counterStore = createStore((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
}));
// Apply middleware
const enhancedStore = applyMiddleware(
counterStore,
logger, // Log all state changes
persist("counter-store") // Save state to localStorage
);
// Now use enhancedStore instead of counterStoreSelecting Partial State
Subscribe to specific parts of your state for better performance:
import { createStore, select } from "@developedbyed/superstate";
const store = createStore(() => ({
user: { name: "John", age: 30 },
settings: { theme: "dark" },
todos: [],
}));
// Subscribe only to the user slice
const userSelector = select(store, (state) => state.user);
userSelector((user) => {
console.log("User changed:", user);
});
// This will trigger the above callback
store.setState({ user: { name: "Jane", age: 28 } });
// This won't trigger the callback
store.setState({ settings: { theme: "light" } });Creating Custom Middleware
You can create your own middleware to extend functionality:
import {
createStore,
applyMiddleware,
Middleware,
} from "@developedbyed/superstate";
// Create a throttle middleware
const throttle =
(delay: number): Middleware =>
(store) => {
const originalSetState = store.setState;
let lastCall = 0;
let timeoutId: any = null;
store.setState = (partial, replace) => {
const now = Date.now();
const remaining = delay - (now - lastCall);
if (remaining <= 0) {
lastCall = now;
originalSetState(partial, replace);
} else {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
lastCall = Date.now();
originalSetState(partial, replace);
}, remaining);
}
};
return store;
};
// Use the custom middleware
const store = createStore(() => ({ count: 0 }));
const throttledStore = applyMiddleware(store, throttle(300));TypeScript Usage
Superstate is built with TypeScript for excellent type inference:
import { createStore } from "@developedbyed/superstate";
interface TodoState {
todos: Array;
addTodo: (text: string) => void;
toggleTodo: (id: number) => void;
clearCompleted: () => void;
}
const useTodoStore = createStore((set, get) => ({
todos: [],
addTodo: (text) =>
set((state) => ({
todos: [...state.todos, { id: Date.now(), text, completed: false }],
})),
toggleTodo: (id) =>
set((state) => ({
todos: state.todos.map((todo) =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
),
})),
clearCompleted: () =>
set((state) => ({
todos: state.todos.filter((todo) => !todo.completed),
})),
}));Integrating with React
While Superstate works with any framework, here's how to use it with React:
import { createStore } from '@developedbyed/superstate';
import { useState, useEffect } from 'react';
// Create a store
const counterStore = createStore((set) => ({
count: 0,
increment: () => set(state => ({ count: state.count + 1 })),
decrement: () => set(state => ({ count: state.count - 1 })),
}));
// Create a custom hook
function useStore(
store: { getState: () => T; subscribe: (listener: (state: T, prevState: T) => void) => () => void },
selector: (state: T) => U
) {
const [state, setState] = useState(() => selector(store.getState()));
useEffect(() => {
return store.subscribe((newState, oldState) => {
const newSelectedState = selector(newState);
const oldSelectedState = selector(oldState);
if (newSelectedState !== oldSelectedState) {
setState(newSelectedState);
}
});
}, [store, selector]);
return state;
}
// Use in component
function Counter() {
const count = useStore(counterStore, state => state.count);
const { increment, decrement } = counterStore.getState();
return (
Count: {count}
+
-
);
}License
MIT ยฉ developedbyed