Shared, not duplicated
Call a store like a hook, in any component or in other stores. The hook runs once per params, however many places call it.
Write a hook once, use it anywhere. One running instance per params, shared by every component and store that calls it.
import { useEffect, useState } from 'react'
import { createStore, AutoRootCtx } from 'react-state-custom'
// 1. A hook, written as usual: the live price of one symbol
const useTickerState = ({ symbol }: { symbol: string }) => {
const [price, setPrice] = useState<number>()
useEffect(() => socket.subscribe(`ticker:${symbol}`, setPrice), [symbol])
return { price }
}
export const { useStore: useTicker } = createStore('ticker', useTickerState)
// 2. Another store uses it, like a hook calling a hook
const usePositionState = ({ symbol }: { symbol: string }) => {
const [position, setPosition] = useState<Position>()
useEffect(() => { fetchPosition(symbol).then(setPosition) }, [symbol])
const { price } = useTicker({ symbol })
return { pnl: price !== undefined && position ? (price - position.entry) * position.qty : undefined }
}
export const { useStore: usePosition } = createStore('position', usePositionState)
// 3. Mount AutoRootCtx once, near the root
<AutoRootCtx />
// 4. Call the stores like hooks, anywhere
const Price = ({ symbol }: { symbol: string }) => {
const { price } = useTicker({ symbol })
return <b>{price ?? '…'}</b>
}
const Pnl = ({ symbol }: { symbol: string }) => {
const { pnl } = usePosition({ symbol })
return <b>{pnl ?? '…'}</b>
}<Price symbol="BTC" /> in the header, another in the order form, and the position store all ask for the BTC ticker: the socket is subscribed once. The price shows on the first tick, the P&L as soon as the position has loaded too. When the last of them unmounts, the subscription is cleaned up. No provider per store, no selectors, no loading logic in the view.
npm install react-state-customA store pays off when several components need the same running piece of state, effects included, per id.
createStore and they run as written.useState.storeRef() reads and drives it from outside, but it runs only under a mounted AutoRootCtx.Sharing changes behaviour: callers with the same params share everything the hook holds. Decide what belongs to the shared instance and what stays with each view; see What an instance shares.