You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Valtio's useSnapshot is incompatible with some use cases that are allowed (and recommended) in React.
It would be really nice if we can detect such cases and warn it.
What's not working
conststate=proxy({text: 'hello',count: 0})constComponent=()=>{constsnap=useSnapshot(state)useEffect(()=>{console.log('something is changed')},[snap])return<div>{snap.text}</div>}
The problem in the example above is when we change the count as ++state.count, the component won't re-render, thus the effect doesn't fire. What's worse is if snap is used in the useEffect callback body, but that's a different story (and already caught by other rules.)
This is not solvable by design and we let people use some workarounds.
Alternative 1
We educate valtio users to use only primitive values for useEffect deps.
If we really want to watch the reference change, we shouldn't use snap, but use state instead.
conststate=proxy({text: 'hello',count: 0})constComponent=()=>{constsnap=useSnapshot(state)useEffect(()=>subscribe(state,()=>{console.log('something is changed')}),[])return<div>{snap.text}</div>}
It's not exactly the same as the original code intention, but in practice, it would cover most use cases.
Idea
I originally thought this misusage can't be caught by our linter, but if we use TypeScript parser, it should be fairly easy to know if an object is the result of useSnapshot, even for nested objects.
I'm not sure if we can change types only for linter. Or, even without types, eslint has clever enough to do flow analysis?
The text was updated successfully, but these errors were encountered:
Thanks for the note.
Yes, v2 will be fixing the memo issue.
However, this case is still troublesome.
conststate=proxy({text: 'hello',count: 0})constComponent=()=>{constsnap=useSnapshot(state)useEffect(()=>{console.log('something is changed')},[snap])return<div>{snap.text}</div>}
Let's leave it open for visibility.
dai-shi
changed the title
Detect misusing snapshot for memo and deps
Detect misusing snapshot for useEffect deps
Apr 14, 2024
Following #40.
Valtio's useSnapshot is incompatible with some use cases that are allowed (and recommended) in React.
It would be really nice if we can detect such cases and warn it.
What's not working
The problem in the example above is when we change the count as
++state.count
, the component won't re-render, thus the effect doesn't fire. What's worse is ifsnap
is used in the useEffect callback body, but that's a different story (and already caught by other rules.)This is not solvable by design and we let people use some workarounds.
Alternative 1
We educate valtio users to use only primitive values for useEffect deps.
The above non-working example would become this:
This style doesn't conflict with React linter.
Alternative 2
If we really want to watch the reference change, we shouldn't use snap, but use state instead.
It's not exactly the same as the original code intention, but in practice, it would cover most use cases.
Idea
I originally thought this misusage can't be caught by our linter, but if we use TypeScript parser, it should be fairly easy to know if an object is the result of
useSnapshot
, even for nested objects.I'm not sure if we can change types only for linter. Or, even without types, eslint has clever enough to do flow analysis?
The text was updated successfully, but these errors were encountered: