@samitouri / QOS-React / commits / 045d4f166d

Fix a context propagation bug (#12708)

* Fix a context propagation bug * Add a regression test

Dan Abramov committed Apr 28, 2018 at 01:52 UTC 045d4f166db6023550b76da6a83fe595a6cdf2f2
2 files changed +78
packages/react-reconciler/src/ReactFiberBeginWork.js
+2
@@ -838,6 +838,8 @@ export default function<T, P, I, TI, HI, PI, C, CC, CX, PL>(
838 }
839 let sibling = nextFiber.sibling;
840 if (sibling !== null) {
841 + // Set the return pointer of the sibling to the work-in-progress fiber.
842 + sibling.return = nextFiber.return;
843 nextFiber = sibling;
844 break;
845 }
packages/react-reconciler/src/__tests__/ReactNewContext-test.internal.js
+76
@@ -1055,6 +1055,82 @@ describe('ReactNewContext', () => {
1055 ReactNoop.flush();
1056 });
1057
1058 + // This is a regression case for https://github.com/facebook/react/issues/12686
1059 + it('does not skip some siblings', () => {
1060 + const Context = React.createContext(0);
1061 +
1062 + class App extends React.Component {
1063 + state = {
1064 + step: 0,
1065 + };
1066 +
1067 + render() {
1068 + ReactNoop.yield('App');
1069 + return (
1070 + <Context.Provider value={this.state.step}>
1071 + <StaticContent />
1072 + {this.state.step > 0 && <Indirection />}
1073 + </Context.Provider>
1074 + );
1075 + }
1076 + }
1077 +
1078 + class StaticContent extends React.PureComponent {
1079 + render() {
1080 + return (
1081 + <React.Fragment>
1082 + <React.Fragment>
1083 + <span prop="static 1" />
1084 + <span prop="static 2" />
1085 + </React.Fragment>
1086 + </React.Fragment>
1087 + );
1088 + }
1089 + }
1090 +
1091 + class Indirection extends React.PureComponent {
1092 + render() {
1093 + return <Consumer />;
1094 + }
1095 + }
1096 +
1097 + function Consumer() {
1098 + return (
1099 + <Context.Consumer>
1100 + {value => {
1101 + ReactNoop.yield('Consumer');
1102 + return <span prop={value} />;
1103 + }}
1104 + </Context.Consumer>
1105 + );
1106 + }
1107 +
1108 + // Initial mount
1109 + let inst;
1110 + ReactNoop.render(<App ref={ref => (inst = ref)} />);
1111 + expect(ReactNoop.flush()).toEqual(['App']);
1112 + expect(ReactNoop.getChildren()).toEqual([
1113 + span('static 1'),
1114 + span('static 2'),
1115 + ]);
1116 + // Update the first time
1117 + inst.setState({step: 1});
1118 + expect(ReactNoop.flush()).toEqual(['App', 'Consumer']);
1119 + expect(ReactNoop.getChildren()).toEqual([
1120 + span('static 1'),
1121 + span('static 2'),
1122 + span(1),
1123 + ]);
1124 + // Update the second time
1125 + inst.setState({step: 2});
1126 + expect(ReactNoop.flush()).toEqual(['App', 'Consumer']);
1127 + expect(ReactNoop.getChildren()).toEqual([
1128 + span('static 1'),
1129 + span('static 2'),
1130 + span(2),
1131 + ]);
1132 + });
1133 +
1134 describe('fuzz test', () => {
1135 const Fragment = React.Fragment;
1136 const contextKeys = ['A', 'B', 'C', 'D', 'E', 'F', 'G'];