Skip to content

Commit

Permalink
Fix multiple renders (#20)
Browse files Browse the repository at this point in the history
  • Loading branch information
hmans authored Sep 16, 2022
1 parent 83c0439 commit c69ab20
Show file tree
Hide file tree
Showing 2 changed files with 10 additions and 5 deletions.
5 changes: 5 additions & 0 deletions .changeset/lemon-pets-add.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"statery": patch
---

Updating the same state property multiple times within the same React side effect would sometimes trigger multiple rerenders of the component, resulting in an infinite loop (for example when writing into the store in a `ref` function.) This has now been fixed.
10 changes: 5 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { useLayoutEffect, useRef, useState } from "react"
/**
* The state objects managed by Statery stores are any string-indexed JavaScript objects.
*/
export interface IState extends Record<string, any> { }
export interface IState extends Record<string, any> {}

/**
* Statery stores wrap around a State object and provide a few functions to update them
Expand Down Expand Up @@ -164,7 +164,7 @@ export const makeStore = <T extends IState>(initialState: T): Store<T> => {
*/
export const useStore = <T extends IState>(store: Store<T>): T => {
/* A cheap version state that we will bump in order to re-render the component. */
const [, setVersion] = useState(0)
const [v, setVersion] = useState(0)

/* A set containing all props that we're interested in. */
const subscribedProps = useConst(() => new Set<keyof T>())
Expand All @@ -181,7 +181,7 @@ export const useStore = <T extends IState>(store: Store<T>): T => {

subscribedProps.forEach((prop) => {
if (initialState[prop] !== store.state[prop]) {
setVersion((v) => v + 1)
setVersion(v + 1)
return
}
})
Expand All @@ -193,14 +193,14 @@ export const useStore = <T extends IState>(store: Store<T>): T => {
/* If there is at least one prop being updated that we're interested in,
bump our local version. */
if (Object.keys(updates).find((prop) => subscribedProps.has(prop))) {
setVersion((v) => v + 1)
setVersion(v + 1)
}
}

/* Mount & unmount the listener */
store.subscribe(listener)
return () => void store.unsubscribe(listener)
}, [store])
}, [store, v])

return new Proxy<Record<any, any>>(
{},
Expand Down

0 comments on commit c69ab20

Please sign in to comment.