Skip to content

Commit 4607937

Browse files
committed
Fixed an issue with simple memo components being updated with new props during context change
1 parent d63cd97 commit 4607937

File tree

3 files changed

+49
-2
lines changed

3 files changed

+49
-2
lines changed

packages/react-reconciler/src/ReactFiberBeginWork.new.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -592,8 +592,9 @@ function updateSimpleMemoComponent(
592592
}
593593
if (current !== null) {
594594
const prevProps = current.memoizedProps;
595+
nextProps = shallowEqual(prevProps, nextProps) ? prevProps : nextProps;
595596
if (
596-
shallowEqual(prevProps, nextProps) &&
597+
prevProps === nextProps &&
597598
current.ref === workInProgress.ref &&
598599
// Prevent bailout if the implementation changed due to hot reload.
599600
(__DEV__ ? workInProgress.type === current.type : true)

packages/react-reconciler/src/ReactFiberBeginWork.old.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -592,8 +592,9 @@ function updateSimpleMemoComponent(
592592
}
593593
if (current !== null) {
594594
const prevProps = current.memoizedProps;
595+
nextProps = shallowEqual(prevProps, nextProps) ? prevProps : nextProps;
595596
if (
596-
shallowEqual(prevProps, nextProps) &&
597+
prevProps === nextProps &&
597598
current.ref === workInProgress.ref &&
598599
// Prevent bailout if the implementation changed due to hot reload.
599600
(__DEV__ ? workInProgress.type === current.type : true)

packages/react-reconciler/src/__tests__/ReactMemo-test.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,51 @@ describe('memo', () => {
179179
expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
180180
});
181181

182+
it('bails out on props referential equality during context change', async () => {
183+
const CountContext = React.createContext(0);
184+
let renderCount = 0;
185+
186+
function Inner(props) {
187+
React.useContext(CountContext);
188+
return React.useMemo(() => {
189+
const text = `Inner render count: ${++renderCount}`;
190+
return <Text text={text} />;
191+
}, [props]);
192+
}
193+
194+
Inner = memo(Inner);
195+
196+
function Outer(props) {
197+
React.useContext(CountContext);
198+
return <Inner />;
199+
}
200+
201+
function Parent({value}) {
202+
return (
203+
<Suspense fallback={<Text text="Loading..." />}>
204+
<CountContext.Provider value={value}>
205+
<Outer />
206+
</CountContext.Provider>
207+
</Suspense>
208+
);
209+
}
210+
211+
let ctxValue = 0;
212+
ReactNoop.render(<Parent value={ctxValue++} />);
213+
expect(Scheduler).toFlushAndYield(['Loading...']);
214+
await Promise.resolve();
215+
expect(Scheduler).toFlushAndYield(['Inner render count: 1']);
216+
expect(ReactNoop.getChildren()).toEqual([
217+
span('Inner render count: 1'),
218+
]);
219+
220+
ReactNoop.render(<Parent value={ctxValue++} />);
221+
expect(Scheduler).toFlushAndYield([]);
222+
expect(ReactNoop.getChildren()).toEqual([
223+
span('Inner render count: 1'),
224+
]);
225+
});
226+
182227
it('accepts custom comparison function', async () => {
183228
function Counter({count}) {
184229
return <Text text={count} />;

0 commit comments

Comments
 (0)