Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/react-reconciler/src/ReactFiberBeginWork.js
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ function updateFunctionalComponent(
nextProps: any,
renderExpirationTime,
) {
const unmaskedContext = getUnmaskedContext(workInProgress, Component);
const unmaskedContext = getUnmaskedContext(workInProgress, Component, true);
const context = getMaskedContext(workInProgress, unmaskedContext);

let nextChildren;
Expand Down Expand Up @@ -674,7 +674,7 @@ function mountIndeterminateComponent(
}
}

const unmaskedContext = getUnmaskedContext(workInProgress, Component);
const unmaskedContext = getUnmaskedContext(workInProgress, Component, false);
const context = getMaskedContext(workInProgress, unmaskedContext);

prepareToReadContext(workInProgress, renderExpirationTime);
Expand Down
16 changes: 12 additions & 4 deletions packages/react-reconciler/src/ReactFiberClassComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,7 @@ function constructClassInstance(
props: any,
renderExpirationTime: ExpirationTime,
): any {
const unmaskedContext = getUnmaskedContext(workInProgress, ctor);
const unmaskedContext = getUnmaskedContext(workInProgress, ctor, true);
const contextTypes = ctor.contextTypes;
const isContextConsumer = contextTypes !== null && contextTypes !== undefined;
const context = isContextConsumer
Expand Down Expand Up @@ -666,7 +666,7 @@ function mountClassInstance(
}

const instance = workInProgress.stateNode;
const unmaskedContext = getUnmaskedContext(workInProgress, ctor);
const unmaskedContext = getUnmaskedContext(workInProgress, ctor, true);

instance.props = newProps;
instance.state = workInProgress.memoizedState;
Expand Down Expand Up @@ -758,7 +758,11 @@ function resumeMountClassInstance(
instance.props = oldProps;

const oldContext = instance.context;
const nextLegacyUnmaskedContext = getUnmaskedContext(workInProgress, ctor);
const nextLegacyUnmaskedContext = getUnmaskedContext(
workInProgress,
ctor,
true,
);
const nextLegacyContext = getMaskedContext(
workInProgress,
nextLegacyUnmaskedContext,
Expand Down Expand Up @@ -897,7 +901,11 @@ function updateClassInstance(
instance.props = oldProps;

const oldContext = instance.context;
const nextLegacyUnmaskedContext = getUnmaskedContext(workInProgress, ctor);
const nextLegacyUnmaskedContext = getUnmaskedContext(
workInProgress,
ctor,
true,
);
const nextLegacyContext = getMaskedContext(
workInProgress,
nextLegacyUnmaskedContext,
Expand Down
6 changes: 3 additions & 3 deletions packages/react-reconciler/src/ReactFiberContext.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,11 @@ let previousContext: Object = emptyContextObject;
function getUnmaskedContext(
workInProgress: Fiber,
Component: Function,
didPushOwnContextIfProvider: boolean,
): Object {
const hasOwnContext = isContextProvider(Component);
if (hasOwnContext) {
if (didPushOwnContextIfProvider && isContextProvider(Component)) {
// If the fiber is a context provider itself, when we read its context
// we have already pushed its own child context on the stack. A context
// we may have already pushed its own child context on the stack. A context
// provider should not "see" its own child context. Therefore we read the
// previous (parent) context instead for a context provider.
return previousContext;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2030,6 +2030,39 @@ describe('ReactIncremental', () => {
]);
});

it('does not leak own context into context provider (factory components)', () => {
const ops = [];
function Recurse(props, context) {
return {
getChildContext() {
return {n: (context.n || 3) - 1};
},
render() {
ops.push('Recurse ' + JSON.stringify(context));
if (context.n === 0) {
return null;
}
return <Recurse />;
},
};
}
Recurse.contextTypes = {
n: PropTypes.number,
};
Recurse.childContextTypes = {
n: PropTypes.number,
};

ReactNoop.render(<Recurse />);
ReactNoop.flush();
expect(ops).toEqual([
'Recurse {}',
'Recurse {"n":2}',
'Recurse {"n":1}',
'Recurse {"n":0}',
]);
});

it('provides context when reusing work', () => {
const ops = [];

Expand Down