Skip to content

Commit 3bc5595

Browse files
authored
Merge pull request #8742 from bvaughn/stack-fiber-gcc-warning
Warn about missing getChildContext method
2 parents c61148c + 7a2e35b commit 3bc5595

File tree

5 files changed

+137
-1
lines changed

5 files changed

+137
-1
lines changed

scripts/fiber/tests-passing.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,8 @@ src/isomorphic/classic/__tests__/ReactContextValidator-test.js
157157
* should pass next context to lifecycles
158158
* should check context types
159159
* should check child context types
160+
* should warn (but not error) if getChildContext method is missing
161+
* should pass parent context if getChildContext method is missing
160162

161163
src/isomorphic/classic/class/__tests__/ReactBind-test.js
162164
* Holds reference to instance

src/isomorphic/classic/__tests__/ReactContextValidator-test.js

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,4 +289,91 @@ describe('ReactContextValidator', () => {
289289
expectDev(console.error.calls.count()).toBe(2);
290290
});
291291

292+
// TODO (bvaughn) Remove this test and the associated behavior in the future.
293+
// It has only been added in Fiber to match the (unintentional) behavior in Stack.
294+
it('should warn (but not error) if getChildContext method is missing', () => {
295+
spyOn(console, 'error');
296+
297+
class ComponentA extends React.Component {
298+
static childContextTypes = {
299+
foo: React.PropTypes.string.isRequired,
300+
};
301+
render() {
302+
return <div />;
303+
}
304+
}
305+
class ComponentB extends React.Component {
306+
static childContextTypes = {
307+
foo: React.PropTypes.string.isRequired,
308+
};
309+
render() {
310+
return <div />;
311+
}
312+
}
313+
314+
ReactTestUtils.renderIntoDocument(<ComponentA/>);
315+
expectDev(console.error.calls.count()).toBe(1);
316+
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
317+
'Warning: ComponentA.childContextTypes is specified but there is no ' +
318+
'getChildContext() method on the instance. You can either define ' +
319+
'getChildContext() on ComponentA or remove childContextTypes from it.'
320+
);
321+
322+
// Warnings should be deduped by component type
323+
ReactTestUtils.renderIntoDocument(<ComponentA/>);
324+
expectDev(console.error.calls.count()).toBe(1);
325+
ReactTestUtils.renderIntoDocument(<ComponentB/>);
326+
expectDev(console.error.calls.count()).toBe(2);
327+
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(1)[0])).toBe(
328+
'Warning: ComponentB.childContextTypes is specified but there is no ' +
329+
'getChildContext() method on the instance. You can either define ' +
330+
'getChildContext() on ComponentB or remove childContextTypes from it.'
331+
);
332+
});
333+
334+
// TODO (bvaughn) Remove this test and the associated behavior in the future.
335+
// It has only been added in Fiber to match the (unintentional) behavior in Stack.
336+
it('should pass parent context if getChildContext method is missing', () => {
337+
spyOn(console, 'error');
338+
339+
class ParentContextProvider extends React.Component {
340+
static childContextTypes = {
341+
foo: React.PropTypes.number,
342+
};
343+
getChildContext() {
344+
return {
345+
foo: 'FOO',
346+
};
347+
}
348+
render() {
349+
return <MiddleMissingContext />;
350+
}
351+
}
352+
353+
class MiddleMissingContext extends React.Component {
354+
static childContextTypes = {
355+
bar: React.PropTypes.string.isRequired,
356+
};
357+
render() {
358+
return <ChildContextConsumer />;
359+
}
360+
}
361+
362+
var childContext;
363+
var ChildContextConsumer = React.createClass({
364+
contextTypes: {
365+
bar: React.PropTypes.string.isRequired,
366+
foo: React.PropTypes.string.isRequired,
367+
},
368+
render: function() {
369+
childContext = this.context;
370+
return <div />;
371+
},
372+
});
373+
374+
ReactTestUtils.renderIntoDocument(<ParentContextProvider/>);
375+
expect(childContext.bar).toBeUndefined();
376+
expect(childContext.foo).toBe('FOO');
377+
});
378+
292379
});

src/renderers/shared/fiber/ReactFiberContext.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import type { StackCursor } from 'ReactFiberStack';
1717

1818
var emptyObject = require('emptyObject');
1919
var invariant = require('invariant');
20+
var warning = require('warning');
2021
var {
2122
getComponentName,
2223
isFiberMounted,
@@ -33,6 +34,7 @@ const {
3334

3435
if (__DEV__) {
3536
var checkReactTypeSpec = require('checkReactTypeSpec');
37+
var warnedAboutMissingGetChildContext = {};
3638
}
3739

3840
// A cursor to the current merged context object on the stack.
@@ -141,6 +143,28 @@ exports.pushTopLevelContextObject = function(fiber : Fiber, context : Object, di
141143
function processChildContext(fiber : Fiber, parentContext : Object, isReconciling : boolean): Object {
142144
const instance = fiber.stateNode;
143145
const childContextTypes = fiber.type.childContextTypes;
146+
147+
// TODO (bvaughn) Replace this behavior with an invariant() in the future.
148+
// It has only been added in Fiber to match the (unintentional) behavior in Stack.
149+
if (typeof instance.getChildContext !== 'function') {
150+
if (__DEV__) {
151+
const componentName = getComponentName(fiber);
152+
153+
if (!warnedAboutMissingGetChildContext[componentName]) {
154+
warnedAboutMissingGetChildContext[componentName] = true;
155+
warning(
156+
false,
157+
'%s.childContextTypes is specified but there is no getChildContext() method ' +
158+
'on the instance. You can either define getChildContext() on %s or remove ' +
159+
'childContextTypes from it.',
160+
componentName,
161+
componentName,
162+
);
163+
}
164+
}
165+
return parentContext;
166+
}
167+
144168
const childContext = instance.getChildContext();
145169
for (let contextKey in childContext) {
146170
invariant(

src/renderers/shared/shared/__tests__/ReactStatelessComponent-test.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,17 @@ describe('ReactStatelessComponent', () => {
118118

119119
ReactDOM.render(<StatelessComponentWithChildContext name="A" />, container);
120120

121-
expectDev(console.error.calls.count()).toBe(1);
121+
expectDev(console.error.calls.count()).toBe(2);
122122
expectDev(console.error.calls.argsFor(0)[0]).toContain(
123123
'StatelessComponentWithChildContext(...): childContextTypes cannot ' +
124124
'be defined on a functional component.'
125125
);
126+
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(1)[0])).toBe(
127+
'Warning: StatelessComponentWithChildContext.childContextTypes is specified ' +
128+
'but there is no getChildContext() method on the instance. You can either ' +
129+
'define getChildContext() on StatelessComponentWithChildContext or remove ' +
130+
'childContextTypes from it.'
131+
);
126132
});
127133

128134
if (!ReactDOMFeatureFlags.useFiber) {

src/renderers/shared/stack/reconciler/ReactCompositeComponent.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ var ReactReconciler = require('ReactReconciler');
2424

2525
if (__DEV__) {
2626
var checkReactTypeSpec = require('checkReactTypeSpec');
27+
var warningAboutMissingGetChildContext = {};
2728
}
2829

2930
var emptyObject = require('emptyObject');
@@ -698,6 +699,22 @@ var ReactCompositeComponent = {
698699
);
699700
}
700701
return Object.assign({}, currentContext, childContext);
702+
} else {
703+
if (__DEV__) {
704+
const componentName = this.getName();
705+
706+
if (!warningAboutMissingGetChildContext[componentName]) {
707+
warningAboutMissingGetChildContext[componentName] = true;
708+
warning(
709+
!Component.childContextTypes,
710+
'%s.childContextTypes is specified but there is no getChildContext() method ' +
711+
'on the instance. You can either define getChildContext() on %s or remove ' +
712+
'childContextTypes from it.',
713+
componentName,
714+
componentName,
715+
);
716+
}
717+
}
701718
}
702719
return currentContext;
703720
},

0 commit comments

Comments
 (0)