Skip to content

Instantly share code, notes, and snippets.

@multivoltage
Last active February 5, 2025 09:39
Show Gist options
  • Save multivoltage/55d4c4176a90781ca229a323612d2486 to your computer and use it in GitHub Desktop.
Save multivoltage/55d4c4176a90781ca229a323612d2486 to your computer and use it in GitHub Desktop.
Simple store in React 19 without Provider/Consumer/Context
/**
* create fast and working minimal store in react 19 without Context/Provider.
* Usage:
* // navbar.tsx
* "use client";
* function MyNavbar(){
* const { store: { cart }} = useMinimalStore()
* return <nav>you have {cart.productsCount}</nav>
* }
*
* // productItem.tsx
* "use client";
* function Item(item: IProduct){
* const { selectProduct } = useMinimalStore()
* return <button onCLick={() => selectProduct(item)}>item 666</button>
* }
*/
import { useSyncExternalStore } from "react";
import { IProduct } from "./types";
export type Listener = () => void;
type MinimalStore = {
selectedProduct?: IProduct;
cart: {
productsCount: number;
totalPrice: number;
};
};
function createStore({ initialState }: { initialState: MinimalStore }) {
let subscribers: Listener[] = [];
let state = initialState;
const notifyStateChanged = () => {
subscribers.forEach((fn) => fn());
};
return {
subscribe(fn: Listener) {
subscribers.push(fn);
return () => {
subscribers = subscribers.filter((listener) => listener !== fn);
};
},
getSnapshot() {
return state;
},
setState(newState: MinimalStore) {
state = newState;
notifyStateChanged();
},
};
}
export function createUseStore(initialState: MinimalStore) {
const store = createStore({ initialState });
return () => {
return {
store: useSyncExternalStore(store.subscribe, store.getSnapshot),
addProductToCard: (product: IProduct, quantity: number) => {
const amountToSum = product.price * quantity;
store.setState({
...store.getSnapshot(),
cart: {
...store.getSnapshot().cart,
productsCount: store.getSnapshot().cart.productsCount + quantity,
totalPrice: store.getSnapshot().cart.totalPrice + amountToSum,
},
});
},
selectProduct: (product: IProduct) => {
store.setState({
...store.getSnapshot(),
selectedProduct: product,
});
},
} as const;
};
}
export const useMinimalStore = createUseStore({
cart: {
productsCount: 0,
totalPrice: 0,
},
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment