Skip to content

Commit 90cbc6d

Browse files
committed
refactor(brownie): require selector param in useStore
1 parent 5f1c6a1 commit 90cbc6d

3 files changed

Lines changed: 20 additions & 50 deletions

File tree

docs/docs/brownie/typescript-usage.mdx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,36 +4,36 @@ Use stores in React Native with the `useStore` hook.
44

55
## useStore Hook
66

7-
The `useStore` hook provides a `useState`-like API for accessing shared state:
7+
The `useStore` hook provides a `useState`-like API for accessing shared state. It requires a selector function to subscribe to a specific slice of state. The component only re-renders when the selected value changes.
88

99
```tsx
1010
import { useStore } from '@callstack/brownie';
1111

1212
function Counter() {
13-
const [state, setState] = useStore('BrownfieldStore');
13+
// Select the counter slice - only re-renders when counter changes
14+
const [counter, setState] = useStore('BrownfieldStore', (s) => s.counter);
1415

1516
return (
1617
<View>
17-
<Text>Count: {state.counter}</Text>
18+
<Text>Count: {counter}</Text>
1819
<Button
1920
title="Increment"
20-
onPress={() => setState({ counter: state.counter + 1 })}
21+
onPress={() => setState({ counter: counter + 1 })}
2122
/>
2223
</View>
2324
);
2425
}
2526
```
2627

27-
## Selectors
28-
29-
Use selectors to subscribe to a slice of state. The component only re-renders when the selected value changes:
30-
3128
```tsx
3229
// Only re-renders when counter changes
3330
const [counter, setState] = useStore('BrownfieldStore', (s) => s.counter);
3431

3532
// Only re-renders when user changes
3633
const [user, setState] = useStore('BrownfieldStore', (s) => s.user);
34+
35+
// Select entire state (re-renders on any change)
36+
const [state, setState] = useStore('BrownfieldStore', (s) => s);
3737
```
3838

3939
## Updating State

packages/brownie/ArchitectureOverview.md

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -307,23 +307,7 @@ packages/brownie/
307307

308308
### React Hook
309309

310-
```ts
311-
// Full state (useState-like API)
312-
const [state, setState] = useStore('BrownfieldStore');
313-
314-
// Read state
315-
console.log(state.counter);
316-
317-
// Update state (partial update)
318-
setState({ counter: state.counter + 1 });
319-
320-
// Update with callback (like useState)
321-
setState((prev) => ({ counter: prev.counter + 1 }));
322-
```
323-
324-
### Selectors
325-
326-
Selectors allow subscribing to a slice of state, reducing unnecessary re-renders:
310+
`useStore` requires a selector function to subscribe to a specific slice of state:
327311

328312
```ts
329313
import { useStore } from '@callstack/brownie';
@@ -333,6 +317,15 @@ const [counter, setState] = useStore('BrownfieldStore', (s) => s.counter);
333317

334318
// Select object
335319
const [user, setState] = useStore('BrownfieldStore', (s) => s.user);
320+
321+
// Select entire state (re-renders on any change)
322+
const [state, setState] = useStore('BrownfieldStore', (s) => s);
323+
324+
// Update state (partial update)
325+
setState({ counter: counter + 1 });
326+
327+
// Update with callback (like useState)
328+
setState((prev) => ({ counter: prev.counter + 1 }));
336329
```
337330

338331
**How it works:**

packages/brownie/src/index.ts

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -95,18 +95,6 @@ export function setState<K extends keyof BrownieStores>(
9595
}
9696
}
9797

98-
const identity = <T>(x: T): T => x;
99-
100-
/**
101-
* React hook for subscribing to a native store with optional selector.
102-
* Inspired by Zustand's useStore implementation.
103-
* @param key Store key registered in StoreManager
104-
* @returns Tuple of [state, setState] for the store
105-
*/
106-
export function useStore<K extends keyof BrownieStores>(
107-
key: K
108-
): [BrownieStores[K], (action: SetStateAction<BrownieStores[K]>) => void];
109-
11098
/**
11199
* React hook for subscribing to a native store with selector.
112100
* Inspired by Zustand's useStore implementation.
@@ -117,23 +105,12 @@ export function useStore<K extends keyof BrownieStores>(
117105
export function useStore<K extends keyof BrownieStores, U>(
118106
key: K,
119107
selector: (state: BrownieStores[K]) => U
120-
): [U, (action: SetStateAction<BrownieStores[K]>) => void];
121-
122-
export function useStore<K extends keyof BrownieStores, U>(
123-
key: K,
124-
selector?: (state: BrownieStores[K]) => U
125-
): [U | BrownieStores[K], (action: SetStateAction<BrownieStores[K]>) => void] {
108+
): [U, (action: SetStateAction<BrownieStores[K]>) => void] {
126109
const sub = useCallback(
127110
(listener: () => void) => subscribe(key, listener),
128111
[key]
129112
);
130-
const snap = useCallback(
131-
() =>
132-
(selector ?? (identity as (state: BrownieStores[K]) => U))(
133-
getSnapshot(key)
134-
),
135-
[key, selector]
136-
);
113+
const snap = useCallback(() => selector(getSnapshot(key)), [key, selector]);
137114

138115
const slice = useSyncExternalStore(sub, snap, snap);
139116

0 commit comments

Comments
 (0)