Skip to content

Commit

Permalink
Rerender on changes since reconciliation phase (#13)
Browse files Browse the repository at this point in the history
  • Loading branch information
hmans authored Aug 20, 2022
1 parent 4ffc7fc commit a5f5533
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/wicked-roses-switch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"statery": patch
---

`useStore` will now force the component to re-render if a change was detected between the React render/reconcile stage and the invocation of the layout effect that actually sets up the subscription listener. This improves reactivity in situations where values were changed in the store during the render phase, or imperatively from outside of your React component tree.
18 changes: 18 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,24 @@ export const useStore = <T extends State>(store: Store<T>): T => {
/* A set containing all props that we're interested in. */
const subscribedProps = useConst(() => new Set<keyof T>())

/* Grab a copy of the state at the time the component is rendering; then, in an effect,
check if there have already been any updates. This can happen because something that
was rendered alongside this component wrote into the store immediately, possibly
through a function ref. If we detect a change related to the props we're interested in,
force the component to reload. */
const initialState = useConst(() => store.state)

useLayoutEffect(() => {
if (store.state === initialState) return

subscribedProps.forEach((prop) => {
if (initialState[prop] !== store.state[prop]) {
setVersion((v) => v + 1)
return
}
})
}, [store])

/* Subscribe to changes in the store. */
useLayoutEffect(() => {
const listener: Listener<T> = (updates: Partial<T>) => {
Expand Down

0 comments on commit a5f5533

Please sign in to comment.