mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
@@ -13,6 +13,7 @@
|
||||
let React;
|
||||
let ReactDOMServer;
|
||||
let PropTypes;
|
||||
let ReactCurrentOwner;
|
||||
|
||||
function normalizeCodeLocInfo(str) {
|
||||
return str && str.replace(/\(at .+?:\d+\)/g, '(at **)');
|
||||
@@ -24,6 +25,9 @@ describe('ReactDOMServer', () => {
|
||||
React = require('react');
|
||||
PropTypes = require('prop-types');
|
||||
ReactDOMServer = require('react-dom/server');
|
||||
ReactCurrentOwner =
|
||||
React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
|
||||
.ReactCurrentOwner;
|
||||
});
|
||||
|
||||
describe('renderToString', () => {
|
||||
@@ -431,6 +435,44 @@ describe('ReactDOMServer', () => {
|
||||
expect(results).toEqual([2, 1, 3, 1]);
|
||||
});
|
||||
|
||||
it('renders with dispatcher.readContext mechanism', () => {
|
||||
const Context = React.createContext(0);
|
||||
|
||||
function readContext(context) {
|
||||
return ReactCurrentOwner.currentDispatcher.readContext(context);
|
||||
}
|
||||
|
||||
function Consumer(props) {
|
||||
return 'Result: ' + readContext(Context);
|
||||
}
|
||||
|
||||
const Indirection = React.Fragment;
|
||||
|
||||
function App(props) {
|
||||
return (
|
||||
<Context.Provider value={props.value}>
|
||||
<Context.Provider value={2}>
|
||||
<Consumer />
|
||||
</Context.Provider>
|
||||
<Indirection>
|
||||
<Indirection>
|
||||
<Consumer />
|
||||
<Context.Provider value={3}>
|
||||
<Consumer />
|
||||
</Context.Provider>
|
||||
</Indirection>
|
||||
</Indirection>
|
||||
<Consumer />
|
||||
</Context.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
const markup = ReactDOMServer.renderToString(<App value={1} />);
|
||||
// Extract the numbers rendered by the consumers
|
||||
const results = markup.match(/\d+/g).map(Number);
|
||||
expect(results).toEqual([2, 1, 3, 1]);
|
||||
});
|
||||
|
||||
it('renders context API, reentrancy', () => {
|
||||
const Context = React.createContext(0);
|
||||
|
||||
|
||||
+52
-37
@@ -75,6 +75,7 @@ const toArray = ((React.Children.toArray: any): toArrayType);
|
||||
// Each stack is an array of frames which may contain nested stacks of elements.
|
||||
let currentDebugStacks = [];
|
||||
|
||||
let ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner;
|
||||
let ReactDebugCurrentFrame;
|
||||
let prevGetCurrentStackImpl = null;
|
||||
let getCurrentServerStackImpl = () => '';
|
||||
@@ -85,6 +86,15 @@ let pushCurrentDebugStack = (stack: Array<Frame>) => {};
|
||||
let pushElementToDebugStack = (element: ReactElement) => {};
|
||||
let popCurrentDebugStack = () => {};
|
||||
|
||||
let Dispatcher = {
|
||||
readContext<T>(
|
||||
context: ReactContext<T>,
|
||||
observedBits: void | number | boolean,
|
||||
): T {
|
||||
return context._currentValue;
|
||||
},
|
||||
};
|
||||
|
||||
if (__DEV__) {
|
||||
ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame;
|
||||
|
||||
@@ -787,49 +797,54 @@ class ReactDOMServerRenderer {
|
||||
return null;
|
||||
}
|
||||
|
||||
let out = '';
|
||||
while (out.length < bytes) {
|
||||
if (this.stack.length === 0) {
|
||||
this.exhausted = true;
|
||||
break;
|
||||
}
|
||||
const frame: Frame = this.stack[this.stack.length - 1];
|
||||
if (frame.childIndex >= frame.children.length) {
|
||||
const footer = frame.footer;
|
||||
out += footer;
|
||||
if (footer !== '') {
|
||||
this.previousWasTextNode = false;
|
||||
ReactCurrentOwner.currentDispatcher = Dispatcher;
|
||||
try {
|
||||
let out = '';
|
||||
while (out.length < bytes) {
|
||||
if (this.stack.length === 0) {
|
||||
this.exhausted = true;
|
||||
break;
|
||||
}
|
||||
this.stack.pop();
|
||||
if (frame.type === 'select') {
|
||||
this.currentSelectValue = null;
|
||||
} else if (
|
||||
frame.type != null &&
|
||||
frame.type.type != null &&
|
||||
frame.type.type.$$typeof === REACT_PROVIDER_TYPE
|
||||
) {
|
||||
const provider: ReactProvider<any> = (frame.type: any);
|
||||
this.popProvider(provider);
|
||||
const frame: Frame = this.stack[this.stack.length - 1];
|
||||
if (frame.childIndex >= frame.children.length) {
|
||||
const footer = frame.footer;
|
||||
out += footer;
|
||||
if (footer !== '') {
|
||||
this.previousWasTextNode = false;
|
||||
}
|
||||
this.stack.pop();
|
||||
if (frame.type === 'select') {
|
||||
this.currentSelectValue = null;
|
||||
} else if (
|
||||
frame.type != null &&
|
||||
frame.type.type != null &&
|
||||
frame.type.type.$$typeof === REACT_PROVIDER_TYPE
|
||||
) {
|
||||
const provider: ReactProvider<any> = (frame.type: any);
|
||||
this.popProvider(provider);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
const child = frame.children[frame.childIndex++];
|
||||
if (__DEV__) {
|
||||
pushCurrentDebugStack(this.stack);
|
||||
// We're starting work on this frame, so reset its inner stack.
|
||||
((frame: any): FrameDev).debugElementStack.length = 0;
|
||||
try {
|
||||
// Be careful! Make sure this matches the PROD path below.
|
||||
const child = frame.children[frame.childIndex++];
|
||||
if (__DEV__) {
|
||||
pushCurrentDebugStack(this.stack);
|
||||
// We're starting work on this frame, so reset its inner stack.
|
||||
((frame: any): FrameDev).debugElementStack.length = 0;
|
||||
try {
|
||||
// Be careful! Make sure this matches the PROD path below.
|
||||
out += this.render(child, frame.context, frame.domNamespace);
|
||||
} finally {
|
||||
popCurrentDebugStack();
|
||||
}
|
||||
} else {
|
||||
// Be careful! Make sure this matches the DEV path above.
|
||||
out += this.render(child, frame.context, frame.domNamespace);
|
||||
} finally {
|
||||
popCurrentDebugStack();
|
||||
}
|
||||
} else {
|
||||
// Be careful! Make sure this matches the DEV path above.
|
||||
out += this.render(child, frame.context, frame.domNamespace);
|
||||
}
|
||||
return out;
|
||||
} finally {
|
||||
ReactCurrentOwner.currentDispatcher = null;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
render(
|
||||
|
||||
Reference in New Issue
Block a user