This React store uses a simple EventTarget-backed implementation to prove out the API for React's upcoming concurrent store (types).
For more info on the React Team's plans for this API, check out the React Labs post:
The store API only differs from React's proposed concurrent store API in that the hook to access the store inside of components is named useStore(), because, well, use() is taken.
export interface Store<out Value, in Action> {
// private brand because only values from `createStore` are useable,
// not arbitrary objects matching the shape.
[STORE]: never;
update: (action: Action) => void;
}
export function createStore<Value>(initialValue: Value): Store<Value, Value>;
export function createStore<Value>(
initialValue: Value,
reducer: (previousValue: Value) => Value,
): Store<Value, void>;
export function createStore<Value, Action>(
initialValue: Value,
reducer?: (previousValue: Value, action: Action) => Value,
): Store<Value, Action>;
// for React's built-in concurrent store, this will just be `use()` as it exists today
export function useStore<Value, Action>(store: Store<Value, Action>): Value;You can see an example usage of this store API in the demo application at /apps/sprinkles-doughnut-shoppe with a live example here.
Create a store:
import { createStore } from "@withsprinkles/store";
export type ViewState = { category: string };
export const viewStore = createStore<ViewState, Partial<ViewState>>(
{ category: "All" },
(state, updates) => ({ ...state, ...updates }),
);Use your store in a component with the hook and it'll update automatically:
import { useStore } from "@withsprinkles/store";
import { doughnuts } from "~/lib/data";
export function ShoppingApp() {
const view = useStore(viewStore);
const categories = [
"All",
...Array.from(new Set(doughnuts.map((d) => d.category))),
];
const filtered =
view.category === "All"
? doughnuts
: doughnuts.filter((d) => d.category === view.category);
return (
<main>
<div>
{categories.map((category) => (
<button
key={category}
type="button"
onClick={() => viewStore.update({ category: category })}
className={view.category === category
? "bg-pink-600 text-white"
: "bg-pink-100 text-pink-800"}
>
{category}
</button>
))}
</div>
<section>
{filtered.map((product) => (
<ProductCard key={product.id} product={product} />
))}
</section>
</main>
);
}