use-persisted-state
use-persisted-state copied to clipboard
The returned setter function is changed in each render
The setter function that is returned is not memoized, because it is always changed into a new function at each render (every invoke of the hook).
Ok, I see in the code now that it is memoized and updates with the state. I guess it has to be that way. It is however a difference from how useState works, which never changes the setter function.
I ran into this too!
Ok, I see in the code now that it is memoized and updates with the state. I guess it has to be that way.
I don't think it has to be this way! Here are the lines that cause persistentSetState
to update every time state
changes:
https://github.com/donavon/use-persisted-state/blob/2a33963050b209f8cc27060a32109978414a4dc7/src/usePersistedState.js#L30-L44
But it could be written like so:
const persistentSetState = useCallback(
(newState) => {
setState((oldState) => {
const newStateValue = typeof newState === "function" ? newState(oldState) : newState
// persist to localStorage
set(key, newStateValue)
// inform all of the other instances in this tab
globalState.current.emit(newState)
return newStateValue
})
},
[set, key]
)
By getting oldState
from the setState
call itself, the callback no longer relies on state
.
I believe this change would also fix #55
In my use case, the reason for that is the key being dynamically generated. For that to work, the createPersistedState
must be inside the React code.
function useMyHook({ id }) {
const useMyState = createPersistedState(`my-${id}`)
const [myState, setMyState] = useMyState()
// ...
}
Accordingly to the library source code, the persistentSetState
callback is updated every time the set
param changes:
https://github.com/donavon/use-persisted-state/blob/f10ad4f08966cc1a3d0944d6aaf8b29b3e9a61d7/src/usePersistedState.js#L43
And this param changes every time the createPersistedState
is called, since the storage is created on every call:
https://github.com/donavon/use-persisted-state/blob/f10ad4f08966cc1a3d0944d6aaf8b29b3e9a61d7/src/index.js#L26
Therefore, the setter changes on every render.
Workaround
function useMyHook({ id }) {
const useMyState = createPersistedState(`my-${id}`)
const [myState, setMyState] = useMyState()
const setMyStateRef = useRef()
setMyStateRef.current = setMyState
// To set the state, setMyStateRef must be used instead of setMyState:
setMyStateRef.current(/* new value */)
}