Comments (4)
Note: The conditions for this bug are really odd, so I'm not sure if what I'm seeing is the whole issue or if there is something else going on. I stumbled this issue when trying to reproduce a different issue I've been seeing with Reusable+React 17: stale values occasionally being returned from the reusable store when using the selector function, but I've been unable to reproduce that issue.
Also wondering if this may be related #123
from reusable.
I think I'm running into a similar/same issue right now with react-native:
const useDoubleCounter = createStore(() => {
const [counterA, setCounterA] = React.useState({ value: 0 })
const [counterB, setCounterB] = React.useState({ value: 0 })
const increment = () => {
const incremented = { value: counterA.value + 1 }
console.debug("Incrementing to " + incremented.value)
setCounterA(incremented)
setCounterB(incremented)
}
console.debug({ counterA, counterB })
return {
counterA,
counterB,
increment
}
})
const CounterView = () => {
const { counterA, counterB, increment } = useDoubleCounter()
return <View style={{ flexDirection: "column", alignItems: "center", flex: 1, justifyContent: "space-evenly" }}>
<Text>{counterA.value}</Text>
<Text>{counterB.value}</Text>
<Button title="Increment" onPress={increment} />
</View>
}
When I push the button, the two console.debug
s print out the correct incremented value, but the result from the useDoubleCounter()
-hook always laggs behind one increment (e.g. pushing the first time prints out "Incrementing to 1", but the Text
-elements will continue to show a "0").
Not wrapping the states in an object makes the issue disappear for some reason.
Trying to update the states multiple times inside the increment
handler with the same value (both using the same object, or a newly created object with the same value) does not hide the issue.
Involved versions of react/reusable:
from reusable.
So one thing I noticed looking at the source code:
At https://github.com/reusablejs/reusable/blob/master/src/react-reusable.tsx#L81
const [localCopy, setLocalCopy] = useState<SelectorValue>(() => selector(store.getCachedValue()));
useEffect(() => {
return store.subscribe((newValue) => {
const selectedNewValue = selector(newValue);
if (!areEqual(selectedNewValue, localCopy)) {
setLocalCopy(() => selectedNewValue);
}
});
}, [store, localCopy, selector, areEqual]);
As useEffect
s are run after the render step, there is a chance of "losing" a notification between the initial state of localCopy
and the store.subscribe
becoming active.
Updating the subscribe
method to force an explicit update (that may be redundant, but should be caught by areEqual
) fixes both, my minimal example from above and a more contrived example that is part of a bigger project I'm working on:
subscribe(callback: StoreValueChangeCallback<HookValue>) {
this.subscribers = [...this.subscribers, callback];
if (this.cachedValue != null) callback(this.getCachedValue())
return () => {
this.subscribers = this.subscribers.filter(sub => sub !== callback)
}
}
If desired, I can turn this into a PR
from reusable.
I also tested that fix against @bucknermr's Sandbox and it appears to solve the issue they're having, too.
from reusable.
Related Issues (20)
- Multiple Stores Question HOT 3
- Passing setup data to Reusable stores HOT 2
- Show github repo under npm package HOT 1
- Are you still using it? HOT 2
- Recoil HOT 3
- Question: Did you use this package with React 17 HOT 10
- Check babel macro correctness
- Add global object for debugging that allows exploring stores and cached values
- Add logger HOT 2
- Support case of nested ReusableProviders HOT 2
- Add example - testing stores
- Add SSR example
- wrong input behaviour only when using store HOT 1
- Code example typo in readme HOT 1
- Is it possible to have multiple root providers and still share the same store HOT 4
- overriding areEqual without using selectors HOT 3
- Error "TypeError r is not a function" occurs when calling store with argument HOT 1
- Having Multiple Reusable provider renders component Multiple times HOT 4
- Forking to Dart/Flutter HOT 8
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from reusable.