Using nanostores as local/component storage in React/Preact #200
-
I'm really liking your Questions
My Exploration...I gather the main motivation with nanostores was to provide shared state management, but it seemed like it might also be possible to use I guess I was hoping to find something in the lib that was analogous to Preact's Preact Signals examples of Shared and Local State/** Preact Signals - Shared State (all component usages in sync) */
const $count = signal(0);
const Counter : FunctionComponent = () => {
const increment = () => $count.value = $count.value + 1;
return <button onClick={increment}>{$count}</button>
};
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode>
<Counter />
<Counter />
</React.StrictMode>,
); /** Preact Signals - Local State (each component has own state) */
const Counter : FunctionComponent = () => {
const count = useSignal(0);
const increment = () => count.value = count.value + 1;
return <button onClick={increment}>{count}</button>
};
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode>
<Counter />
<Counter />
</React.StrictMode>,
); Nanostores exploration with Shared and Local State/** Nanostores - Shared State (all component usages in sync) */
const $shared = map({ count: 0 });
const Counter: FunctionComponent = () => {
const state = useStore($shared);
const increment = () => $shared.set({ count: state.count + 1 });
return <button onClick={increment}>{state.count}</button>
};
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode>
<Counter />
<Counter />
</React.StrictMode>,
); I wasn't able to find a way with nanostores' /** Nanostores - example of Localizing State */
const Counter: FunctionComponent = () => {
const $count = useRef(atom(0));
const count = useStore($count.current);
const increment = () => $count.current.set($count.current.get() + 1);
return <button onClick={increment}>{count}</button>
}; This wasn't very pretty though, so I extracted it into a more generic hook that resembled the API of /** useNanostore - Hook to allow use of nanostore as Local or Shared State */
const isCallback = (maybeFn: unknown): maybeFn is Function => typeof maybeFn === 'function';
const useNanostore = <S extends WritableStore>(store: S) => {
type ValueOrFunction = typeof state | ((cur: typeof state) => typeof state);
const $local = useRef(store);
const state = useStore($local.current);
const setter = (val: ValueOrFunction) => $local.current.set(isCallback(val) ? val(state) : val);
return [ state, setter ] as const;
};
// Usage...
// Initialize and obtain Getter and Setter
const [ state, setState ] = useNanostore(map({ count: 0 }));
// Set state directly
setState({ count: 1 })
// Set state using current value from function
setState(val => ({ ...val, count: val.count + 1 })) This ended up working quite well and allowed for usage of both Shared or Local state... Nanostores examples of Shared and Local State (using custom hook)/** Nanostores - Shared State (all component usages in sync) */
const $shared = map({ count: 0 });
const Counter: FunctionComponent = () => {
const [ state, setState ] = useNanostore($shared);
const increment = () => setState({ count: state.count + 1 });
return <button onClick={increment}>{state.count}</button>
};
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode>
<Counter />
<Counter />
</React.StrictMode>,
); /** Nanostores - Local State (each component has own state) */
const Counter: FunctionComponent = () => {
const [ state, setState ] = useNanostore(map({ count: 0 }));
const increment = () => setState({ count: state.count + 1 });
return <button onClick={increment}>{state.count}</button>
};
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode>
<Counter />
<Counter />
</React.StrictMode>,
); ThoughtsPerhaps I missed something obvious in the lib and maybe none of the above is necessary, but figured I'd share my exploration and ask here incase. If it turns out that the above example is the right/recommended approach, then love for a similar hook to make it into the |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment
-
It is fun experiment. IT was interesting to read the path. Talking about the core API, we are not planning to replace |
Beta Was this translation helpful? Give feedback.
It is fun experiment. IT was interesting to read the path.
Talking about the core API, we are not planning to replace
useState
. The philosophy of Nano Store is to move logic to state manager and keep React components dump (only as simple UI). ReplacinguseState
will move logic back into components and will go against the initial idea.