Skip to content

Commit eba669f

Browse files
committed
Fixes bad intermediate return values from useStoreDependency
Fixes an issue where `useStoreDependency` would return an incorrect intermediate value when a prop change causes the dependency value to change. Now the updated value is returned immediately when the dependency value changes, rather than being set in state but not returned until the next render cycle. === Before The render cycle for a prop change looked like this: 1. component renders: `useStoreDependency` calculates the value, stores it in initial state, and returns it 2. prop change causes component to re-render: `useStoreDependency` calculates new value; if the value changed from (1): stores the new value in state, __but returns the old cached value from (1)__. 3. internal setState call causes component to re-render: `useStoreDependency` calculates new value, but the value doesn't change (props are same as in (2)): finally returns the new value. === After The render cycle is the same as above, except (2) returns the updated value immediately instead of the outdated cached value from (1) Signed-off-by: Gordon McNaughton <[email protected]>
1 parent e7963fe commit eba669f

File tree

2 files changed

+23
-0
lines changed

2 files changed

+23
-0
lines changed

src/dependencies/__tests__/useStoreDependency-test.js

+22
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,28 @@ describe('useStoreDependency', () => {
236236
testHook(useCallback);
237237
});
238238

239+
it('returns the updated store value after prop update', () => {
240+
const Component = ({ factor }) => {
241+
const value = useStoreDependency(multiplyDependency, { factor });
242+
if (value !== factor) {
243+
// We need to throw here rather than relying on the `expect` below
244+
// to catch invalid return values.
245+
//
246+
// This component ends up re-rendering twice: once for the explicit `setProps`
247+
// call, and once for the internal `setState` call inside `useStoreDependency`.
248+
// The expected end state is eventually reached, but intermediate return
249+
// values from `useStoreDependency` could still be wrong.
250+
throw new Error(`incorrect return value from useStoreDependency: expected ${factor} but received ${value}`);
251+
}
252+
return <div data-value={value} />;
253+
};
254+
const rendered = mount(<Component factor={4} />);
255+
expect(rendered.find('div').prop('data-value')).toBe(4);
256+
rendered.setProps({ factor: 8 });
257+
rendered.update();
258+
expect(rendered.find('div').prop('data-value')).toBe(8);
259+
});
260+
239261
it('handles a prop update', () => {
240262
const Component = ({ factor = 4 }) => {
241263
const value = useStoreDependency(multiplyDependency, { factor });

src/dependencies/useStoreDependency.ts

+1
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ function useStoreDependency<Props, DepType>(
102102
const newValue = { dependency: calculate(dependency, props) };
103103
if (!shallowEqual(newValue.dependency, dependencyValue.dependency)) {
104104
setDependencyValue(newValue);
105+
return newValue.dependency;
105106
}
106107
return dependencyValue.dependency;
107108
}

0 commit comments

Comments
 (0)