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'];