From fd66de9e982924d6c6d9b06ccac5c08e29b9544b Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Fri, 27 Apr 2018 23:06:15 +0100 Subject: [PATCH 1/2] Fix a context propagation bug --- packages/react-reconciler/src/ReactFiberBeginWork.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.js b/packages/react-reconciler/src/ReactFiberBeginWork.js index 3c20dceacf3..dcd6246f7c7 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; } From b0f68fef723ce15d8757ed97fa53a78cd41d2dec Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Sat, 28 Apr 2018 01:42:46 +0100 Subject: [PATCH 2/2] Add a regression test --- .../ReactNewContext-test.internal.js | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/packages/react-reconciler/src/__tests__/ReactNewContext-test.internal.js b/packages/react-reconciler/src/__tests__/ReactNewContext-test.internal.js index 0a4763a4fec..9a87f02fda9 100644 --- a/packages/react-reconciler/src/__tests__/ReactNewContext-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactNewContext-test.internal.js @@ -989,6 +989,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'];