@@ -209,52 +209,90 @@ export default function App(){
209209| Static/shared creation | Use ` createSharedState ` , ` createSharedFunction ` , ` createSharedSubscription ` to export reusable, type-safe shared resources that persist across ` clearAll() ` calls. |
210210
211211
212- ## 🏗️ Sharing State (` useSharedState ` )
213- Signature:
214- - ` const [value, setValue] = useSharedState(key, initialValue, scopeName?) `
215- - ` const [value, setValue] = useSharedState(sharedStateCreated) `
212+ ## Selecting State Slices (` useSharedStateSelector ` )
216213
217- Behavior:
218- * First hook call (per key + scope) seeds with ` initialValue ` .
219- * Subsequent mounts with same key+scope ignore their ` initialValue ` (consistent source of truth).
220- * Setter accepts either value or updater ` (prev)=>next ` .
221- * React batching + equality check: listeners fire only when the value reference actually changes.
222- * States created with ` createSharedState ` are ** static** by default and are not removed by ` clear() ` or ` clearAll() ` , ensuring they persist.
214+ When a shared state holds an object, you might only need a small piece of it.
215+ Using ` useSharedState ` will cause your component to re-render whenever * any* part of the object changes.
216+ To optimize performance and avoid unnecessary re-renders, you can use the ` useSharedStateSelector ` hook.
223217
224- ### Examples
225- 1 . Global theme (recommended for large apps)
226- ``` tsx
227- // themeState.ts
228- export const themeState = createSharedState (' light' );
229- // In components
230- const [theme, setTheme] = useSharedState (themeState );
231- ```
232- 2. Isolated wizard progress
233- ` ` ` tsx
234- const wizardProgress = createSharedState(0);
235- <SharedStatesProvider>
236- <Wizard/>
237- </SharedStatesProvider>
238- // In Wizard
239- const [step, setStep] = useSharedState(wizardProgress);
240- ` ` `
241- 3. Forcing cross ‑portal sync
242- ` ` ` tsx
243- const navState = createSharedState('closed', 'nav');
244- <SharedStatesProvider scopeName="nav" children={<PrimaryNav/>} />
245- <Portal>
246- <SharedStatesProvider scopeName="nav" children={<MobileNav/>} />
247- </Portal>
248- // In both navs
249- const [navOpen, setNavOpen] = useSharedState(navState);
250- ` ` `
251- 4. Overriding nearest provider
252- ` ` ` tsx
253- // Even if inside a provider, this explicitly binds to global
254- const globalFlag = createSharedState(false, '_global');
255- const [flag, setFlag] = useSharedState(globalFlag);
256- ` ` `
218+ This hook allows you to subscribe to a specific, memoized slice of a shared state.
219+ Your component will only re-render if the selected value changes.
220+ It uses ` react-fast-compare ` for efficient deep equality checks.
221+
222+ Signature:
223+ - ` const selectedValue = useSharedStateSelector(key, selector, scopeName?) `
224+ - ` const selectedValue = useSharedStateSelector(sharedStateCreated, selector) `
225+
226+ The ` selector ` is a function that receives the full state and returns the desired slice.
227+
228+ ### Example: Subscribing to a slice of a user object
229+
230+ Imagine a shared state for user settings:
257231
232+ ``` tsx
233+ // settingsState.ts
234+ import { createSharedState } from ' react-shared-states' ;
235+
236+ export const settingsState = createSharedState ({
237+ theme: ' dark' ,
238+ notifications: {
239+ email: true ,
240+ push: false ,
241+ },
242+ language: ' en' ,
243+ });
244+ ```
245+
246+ A component that only cares about the theme can use ` useSharedStateSelector ` to avoid re-rendering when, for example, the notification settings change.
247+
248+ ``` tsx
249+ import { useSharedState , useSharedStateSelector } from ' react-shared-states' ;
250+ import { settingsState } from ' ./settingsState' ;
251+
252+ function ThemeDisplay() {
253+ const theme = useSharedStateSelector (settingsState , (settings ) => settings .theme );
254+
255+ console .log (' ThemeDisplay renders' ); // This will only log when the theme changes
256+
257+ return <div >Current theme: { theme } </div >;
258+ }
259+
260+ function NotificationToggle() {
261+ const [settings, setSettings] = useSharedState (settingsState );
262+
263+ const togglePush = () => {
264+ setSettings (s => ({
265+ ... s ,
266+ notifications: { ... s .notifications , push: ! s .notifications .push }
267+ }));
268+ };
269+
270+ return <button onClick = { togglePush } >Toggle Push Notifications</button >;
271+ }
272+ ```
273+
274+ In this example, clicking the ` NotificationToggle ` button will ** not** cause ` ThemeDisplay ` to re-render.
275+
276+ ### A Note on Type Safety
277+
278+ For the best developer experience and full type safety,
279+ it is ** highly recommended** to use ` useSharedStateSelector ` with a statically created shared state object from ` createSharedState ` .
280+
281+ When you use a string key directly, the hook cannot infer the type of the state object.
282+ You would have to provide the types explicitly as generic arguments, or they will default to ` any ` .
283+
284+ ``` tsx
285+ // Less safe: using a string key
286+ // You have to specify the types manually.
287+ const theme = useSharedStateSelector <{ theme: string ; /* ...other props*/ }, ' settings' , string >(
288+ ' settings' ,
289+ (settings ) => settings .theme
290+ );
291+
292+ // Recommended: using a created state object
293+ // Types are inferred automatically!
294+ const theme = useSharedStateSelector (settingsState , (settings ) => settings .theme );
295+ ```
258296
259297## ⚡ Shared Async Functions (` useSharedFunction ` )
260298Signature:
@@ -547,6 +585,12 @@ Returns `[value, setValue]`.
547585### ` useSharedState(sharedStateCreated) `
548586Returns ` [value, setValue] ` .
549587
588+ ### ` useSharedStateSelector(key, selector, scopeName?) `
589+ Returns the selected value.
590+
591+ ### ` useSharedStateSelector(sharedStateCreated, selector) `
592+ Returns the selected value.
593+
550594### ` useSharedFunction(key, fn, scopeName?) `
551595Returns ` { state, trigger, forceTrigger, clear } ` .
552596
@@ -924,6 +968,12 @@ Returns `[value, setValue]`.
924968### ` useSharedState(sharedStateCreated) `
925969Returns ` [value, setValue] ` .
926970
971+ ### ` useSharedStateSelector(key, selector, scopeName?) `
972+ Returns the selected value.
973+
974+ ### ` useSharedStateSelector(sharedStateCreated, selector) `
975+ Returns the selected value.
976+
927977### ` useSharedFunction(key, fn, scopeName?) `
928978Returns ` { state, trigger, forceTrigger, clear } ` .
929979
0 commit comments