From 045d4f166db6023550b76da6a83fe595a6cdf2f2 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Sat, 28 Apr 2018 01:52:48 +0100 Subject: [PATCH] Fix a context propagation bug (#12708) * Fix a context propagation bug * Add a regression test --- .../src/ReactFiberBeginWork.js | 2 + .../ReactNewContext-test.internal.js | 76 +++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.js b/packages/react-reconciler/src/ReactFiberBeginWork.js index 527e6787d1..76f93beac0 100644 --- a/packages/react-reconciler/src/ReactFiberBeginWork.js +++ b/packages/react-reconciler/src/ReactFiberBeginWork.js @@ -838,6 +838,8 @@ export default function( } let sibling = nextFiber.sibling; if (sibling !== null) { + // Set the return pointer of the sibling to the work-in-progress fiber. + sibling.return = nextFiber.return; nextFiber = sibling; break; } diff --git a/packages/react-reconciler/src/__tests__/ReactNewContext-test.internal.js b/packages/react-reconciler/src/__tests__/ReactNewContext-test.internal.js index db2703d3a7..480b4b0021 100644 --- a/packages/react-reconciler/src/__tests__/ReactNewContext-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactNewContext-test.internal.js @@ -1055,6 +1055,82 @@ describe('ReactNewContext', () => { ReactNoop.flush(); }); + // This is a regression case for https://github.com/facebook/react/issues/12686 + it('does not skip some siblings', () => { + const Context = React.createContext(0); + + class App extends React.Component { + state = { + step: 0, + }; + + render() { + ReactNoop.yield('App'); + return ( + + + {this.state.step > 0 && } + + ); + } + } + + class StaticContent extends React.PureComponent { + render() { + return ( + + + + + + + ); + } + } + + class Indirection extends React.PureComponent { + render() { + return ; + } + } + + function Consumer() { + return ( + + {value => { + ReactNoop.yield('Consumer'); + return ; + }} + + ); + } + + // Initial mount + let inst; + ReactNoop.render( (inst = ref)} />); + expect(ReactNoop.flush()).toEqual(['App']); + expect(ReactNoop.getChildren()).toEqual([ + span('static 1'), + span('static 2'), + ]); + // Update the first time + inst.setState({step: 1}); + expect(ReactNoop.flush()).toEqual(['App', 'Consumer']); + expect(ReactNoop.getChildren()).toEqual([ + span('static 1'), + span('static 2'), + span(1), + ]); + // Update the second time + inst.setState({step: 2}); + expect(ReactNoop.flush()).toEqual(['App', 'Consumer']); + expect(ReactNoop.getChildren()).toEqual([ + span('static 1'), + span('static 2'), + span(2), + ]); + }); + describe('fuzz test', () => { const Fragment = React.Fragment; const contextKeys = ['A', 'B', 'C', 'D', 'E', 'F', 'G'];