Ignore SSR warning using explicit suppressHydrationWarning option (#11126)
* Pass parent type and props to insert/delete hydration warning hooks For this to work, we need to split the API into a container and normal version. Since the root doesn't have a type nor props. * Ignore SSR warning using explicit suppressHydrationWarning option This lets you ignore the warning on a single element and its direct child content. This is useful for simple fields that you're expecting to fail such as time stamps. Note that this still won't patch up such content so it'll remain inconsistent. It's also not suitable for nested complex content that may change. * Suppress warning of inserted/deleted direct children * Add fixture testing hydration warning Also fixing the render->hydrate API change in the fixture * Add hooks when text hydration doesn't match up The purpose of these hooks is to pass the parent context to them. I don't want to do that in the normal hydrateTextInstance hooks since this is only used in DEV. This is also in line with what happens if there is no text instance at all and we invoke didNotFindHydratableTextInstance. * Move mismatch text hydration warning to the new hooks This lets us ignore this call when we have parent props available and the suppression flag is set.
This commit is contained in:
parent
5744571140
commit
4131af3e4b
|
@ -15,6 +15,9 @@ export default class Page extends Component {
|
|||
);
|
||||
return (
|
||||
<div>
|
||||
<p suppressHydrationWarning={true}>
|
||||
A random number: {Math.random()}
|
||||
</p>
|
||||
<p>
|
||||
{!this.state.active ? link : 'Thanks!'}
|
||||
</p>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import {render} from 'react-dom';
|
||||
import {hydrate} from 'react-dom';
|
||||
|
||||
import App from './components/App';
|
||||
|
||||
render(<App assets={window.assetManifest} />, document);
|
||||
hydrate(<App assets={window.assetManifest} />, document);
|
||||
|
|
|
@ -53,6 +53,7 @@ var registrationNameModules = EventPluginRegistry.registrationNameModules;
|
|||
|
||||
var DANGEROUSLY_SET_INNER_HTML = 'dangerouslySetInnerHTML';
|
||||
var SUPPRESS_CONTENT_EDITABLE_WARNING = 'suppressContentEditableWarning';
|
||||
var SUPPRESS_HYDRATION_WARNING = 'suppressHydrationWarning';
|
||||
var CHILDREN = 'children';
|
||||
var STYLE = 'style';
|
||||
var HTML = '__html';
|
||||
|
@ -273,7 +274,10 @@ function setInitialDOMProperties(
|
|||
} else if (typeof nextProp === 'number') {
|
||||
setTextContent(domElement, '' + nextProp);
|
||||
}
|
||||
} else if (propKey === SUPPRESS_CONTENT_EDITABLE_WARNING) {
|
||||
} else if (
|
||||
propKey === SUPPRESS_CONTENT_EDITABLE_WARNING ||
|
||||
propKey === SUPPRESS_HYDRATION_WARNING
|
||||
) {
|
||||
// Noop
|
||||
} else if (registrationNameModules.hasOwnProperty(propKey)) {
|
||||
if (nextProp != null) {
|
||||
|
@ -664,7 +668,10 @@ var ReactDOMFiberComponent = {
|
|||
propKey === CHILDREN
|
||||
) {
|
||||
// Noop. This is handled by the clear text mechanism.
|
||||
} else if (propKey === SUPPRESS_CONTENT_EDITABLE_WARNING) {
|
||||
} else if (
|
||||
propKey === SUPPRESS_CONTENT_EDITABLE_WARNING ||
|
||||
propKey === SUPPRESS_HYDRATION_WARNING
|
||||
) {
|
||||
// Noop
|
||||
} else if (registrationNameModules.hasOwnProperty(propKey)) {
|
||||
// This is a special case. If any listener updates we need to ensure
|
||||
|
@ -750,7 +757,10 @@ var ReactDOMFiberComponent = {
|
|||
) {
|
||||
(updatePayload = updatePayload || []).push(propKey, '' + nextProp);
|
||||
}
|
||||
} else if (propKey === SUPPRESS_CONTENT_EDITABLE_WARNING) {
|
||||
} else if (
|
||||
propKey === SUPPRESS_CONTENT_EDITABLE_WARNING ||
|
||||
propKey === SUPPRESS_HYDRATION_WARNING
|
||||
) {
|
||||
// Noop
|
||||
} else if (registrationNameModules.hasOwnProperty(propKey)) {
|
||||
if (nextProp != null) {
|
||||
|
@ -828,6 +838,8 @@ var ReactDOMFiberComponent = {
|
|||
rootContainerElement: Element | Document,
|
||||
): null | Array<mixed> {
|
||||
if (__DEV__) {
|
||||
var suppressHydrationWarning =
|
||||
rawProps[SUPPRESS_HYDRATION_WARNING] === true;
|
||||
var isCustomComponentTag = isCustomComponent(tag, rawProps);
|
||||
validatePropertiesInDevelopment(tag, rawProps);
|
||||
if (isCustomComponentTag && !didWarnShadyDOM && domElement.shadyRoot) {
|
||||
|
@ -986,14 +998,14 @@ var ReactDOMFiberComponent = {
|
|||
// TODO: Should we use domElement.firstChild.nodeValue to compare?
|
||||
if (typeof nextProp === 'string') {
|
||||
if (domElement.textContent !== nextProp) {
|
||||
if (__DEV__) {
|
||||
if (__DEV__ && !suppressHydrationWarning) {
|
||||
warnForTextDifference(domElement.textContent, nextProp);
|
||||
}
|
||||
updatePayload = [CHILDREN, nextProp];
|
||||
}
|
||||
} else if (typeof nextProp === 'number') {
|
||||
if (domElement.textContent !== '' + nextProp) {
|
||||
if (__DEV__) {
|
||||
if (__DEV__ && !suppressHydrationWarning) {
|
||||
warnForTextDifference(domElement.textContent, nextProp);
|
||||
}
|
||||
updatePayload = [CHILDREN, '' + nextProp];
|
||||
|
@ -1010,8 +1022,11 @@ var ReactDOMFiberComponent = {
|
|||
// Validate that the properties correspond to their expected values.
|
||||
var serverValue;
|
||||
var propertyInfo;
|
||||
if (
|
||||
if (suppressHydrationWarning) {
|
||||
// Don't bother comparing. We're ignoring all these warnings.
|
||||
} else if (
|
||||
propKey === SUPPRESS_CONTENT_EDITABLE_WARNING ||
|
||||
propKey === SUPPRESS_HYDRATION_WARNING ||
|
||||
// Controlled attributes are not validated
|
||||
// TODO: Only ignore them on controlled tags.
|
||||
propKey === 'value' ||
|
||||
|
@ -1085,7 +1100,7 @@ var ReactDOMFiberComponent = {
|
|||
|
||||
if (__DEV__) {
|
||||
// $FlowFixMe - Should be inferred as not undefined.
|
||||
if (extraAttributeNames.size > 0) {
|
||||
if (extraAttributeNames.size > 0 && !suppressHydrationWarning) {
|
||||
// $FlowFixMe - Should be inferred as not undefined.
|
||||
warnForExtraAttributes(extraAttributeNames);
|
||||
}
|
||||
|
@ -1125,14 +1140,15 @@ var ReactDOMFiberComponent = {
|
|||
|
||||
diffHydratedText(textNode: Text, text: string): boolean {
|
||||
const isDifferent = textNode.nodeValue !== text;
|
||||
if (__DEV__) {
|
||||
if (isDifferent) {
|
||||
warnForTextDifference(textNode.nodeValue, text);
|
||||
}
|
||||
}
|
||||
return isDifferent;
|
||||
},
|
||||
|
||||
warnForUnmatchedText(textNode: Text, text: string) {
|
||||
if (__DEV__) {
|
||||
warnForTextDifference(textNode.nodeValue, text);
|
||||
}
|
||||
},
|
||||
|
||||
warnForDeletedHydratableElement(
|
||||
parentNode: Element | Document,
|
||||
child: Element,
|
||||
|
|
|
@ -50,6 +50,7 @@ var {
|
|||
updateProperties,
|
||||
diffHydratedProperties,
|
||||
diffHydratedText,
|
||||
warnForUnmatchedText,
|
||||
warnForDeletedHydratableElement,
|
||||
warnForDeletedHydratableText,
|
||||
warnForInsertedHydratedElement,
|
||||
|
@ -58,6 +59,7 @@ var {
|
|||
var {precacheFiberNode, updateFiberProps} = ReactDOMComponentTree;
|
||||
|
||||
if (__DEV__) {
|
||||
var SUPPRESS_HYDRATION_WARNING = 'suppressHydrationWarning';
|
||||
var lowPriorityWarning = require('lowPriorityWarning');
|
||||
var warning = require('fbjs/lib/warning');
|
||||
var validateDOMNesting = require('validateDOMNesting');
|
||||
|
@ -99,6 +101,7 @@ type Props = {
|
|||
autoFocus?: boolean,
|
||||
children?: mixed,
|
||||
hidden?: boolean,
|
||||
suppressHydrationWarning?: boolean,
|
||||
};
|
||||
type Instance = Element;
|
||||
type TextInstance = Text;
|
||||
|
@ -523,30 +526,96 @@ var DOMRenderer = ReactFiberReconciler({
|
|||
return diffHydratedText(textInstance, text);
|
||||
},
|
||||
|
||||
didNotHydrateInstance(
|
||||
parentInstance: Instance | Container,
|
||||
didNotMatchHydratedContainerTextInstance(
|
||||
parentContainer: Container,
|
||||
textInstance: TextInstance,
|
||||
text: string,
|
||||
) {
|
||||
if (__DEV__) {
|
||||
warnForUnmatchedText(textInstance, text);
|
||||
}
|
||||
},
|
||||
|
||||
didNotMatchHydratedTextInstance(
|
||||
parentType: string,
|
||||
parentProps: Props,
|
||||
parentInstance: Instance,
|
||||
textInstance: TextInstance,
|
||||
text: string,
|
||||
) {
|
||||
if (__DEV__ && parentProps[SUPPRESS_HYDRATION_WARNING] !== true) {
|
||||
warnForUnmatchedText(textInstance, text);
|
||||
}
|
||||
},
|
||||
|
||||
didNotHydrateContainerInstance(
|
||||
parentContainer: Container,
|
||||
instance: Instance | TextInstance,
|
||||
) {
|
||||
if (instance.nodeType === 1) {
|
||||
warnForDeletedHydratableElement(parentInstance, (instance: any));
|
||||
} else {
|
||||
warnForDeletedHydratableText(parentInstance, (instance: any));
|
||||
if (__DEV__) {
|
||||
if (instance.nodeType === 1) {
|
||||
warnForDeletedHydratableElement(parentContainer, (instance: any));
|
||||
} else {
|
||||
warnForDeletedHydratableText(parentContainer, (instance: any));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
didNotHydrateInstance(
|
||||
parentType: string,
|
||||
parentProps: Props,
|
||||
parentInstance: Instance,
|
||||
instance: Instance | TextInstance,
|
||||
) {
|
||||
if (__DEV__ && parentProps[SUPPRESS_HYDRATION_WARNING] !== true) {
|
||||
if (instance.nodeType === 1) {
|
||||
warnForDeletedHydratableElement(parentInstance, (instance: any));
|
||||
} else {
|
||||
warnForDeletedHydratableText(parentInstance, (instance: any));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
didNotFindHydratableContainerInstance(
|
||||
parentContainer: Container,
|
||||
type: string,
|
||||
props: Props,
|
||||
) {
|
||||
if (__DEV__) {
|
||||
warnForInsertedHydratedElement(parentContainer, type, props);
|
||||
}
|
||||
},
|
||||
|
||||
didNotFindHydratableContainerTextInstance(
|
||||
parentContainer: Container,
|
||||
text: string,
|
||||
) {
|
||||
if (__DEV__) {
|
||||
warnForInsertedHydratedText(parentContainer, text);
|
||||
}
|
||||
},
|
||||
|
||||
didNotFindHydratableInstance(
|
||||
parentInstance: Instance | Container,
|
||||
parentType: string,
|
||||
parentProps: Props,
|
||||
parentInstance: Instance,
|
||||
type: string,
|
||||
props: Props,
|
||||
) {
|
||||
warnForInsertedHydratedElement(parentInstance, type, props);
|
||||
if (__DEV__ && parentProps[SUPPRESS_HYDRATION_WARNING] !== true) {
|
||||
warnForInsertedHydratedElement(parentInstance, type, props);
|
||||
}
|
||||
},
|
||||
|
||||
didNotFindHydratableTextInstance(
|
||||
parentInstance: Instance | Container,
|
||||
parentType: string,
|
||||
parentProps: Props,
|
||||
parentInstance: Instance,
|
||||
text: string,
|
||||
) {
|
||||
warnForInsertedHydratedText(parentInstance, text);
|
||||
if (__DEV__ && parentProps[SUPPRESS_HYDRATION_WARNING] !== true) {
|
||||
warnForInsertedHydratedText(parentInstance, text);
|
||||
}
|
||||
},
|
||||
|
||||
scheduleDeferredCallback: ReactDOMFrameScheduling.rIC,
|
||||
|
|
|
@ -21,6 +21,7 @@ var RESERVED_PROPS = {
|
|||
defaultChecked: true,
|
||||
innerHTML: true,
|
||||
suppressContentEditableWarning: true,
|
||||
suppressHydrationWarning: true,
|
||||
style: true,
|
||||
};
|
||||
|
||||
|
|
|
@ -318,6 +318,7 @@ describe('ReactDOMComponent', () => {
|
|||
<my-component
|
||||
children={['foo']}
|
||||
suppressContentEditableWarning={true}
|
||||
suppressHydrationWarning={true}
|
||||
/>,
|
||||
container,
|
||||
);
|
||||
|
@ -325,11 +326,15 @@ describe('ReactDOMComponent', () => {
|
|||
expect(
|
||||
container.firstChild.hasAttribute('suppressContentEditableWarning'),
|
||||
).toBe(false);
|
||||
expect(
|
||||
container.firstChild.hasAttribute('suppressHydrationWarning'),
|
||||
).toBe(false);
|
||||
|
||||
ReactDOM.render(
|
||||
<my-component
|
||||
children={['bar']}
|
||||
suppressContentEditableWarning={false}
|
||||
suppressHydrationWarning={false}
|
||||
/>,
|
||||
container,
|
||||
);
|
||||
|
@ -337,6 +342,9 @@ describe('ReactDOMComponent', () => {
|
|||
expect(
|
||||
container.firstChild.hasAttribute('suppressContentEditableWarning'),
|
||||
).toBe(false);
|
||||
expect(
|
||||
container.firstChild.hasAttribute('suppressHydrationWarning'),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('should skip dangerouslySetInnerHTML on web components', () => {
|
||||
|
|
|
@ -725,6 +725,16 @@ describe('ReactDOMServerIntegration', () => {
|
|||
);
|
||||
expect(e.getAttribute('dangerouslySetInnerHTML')).toBe(null);
|
||||
});
|
||||
|
||||
itRenders('no suppressContentEditableWarning attribute', async render => {
|
||||
const e = await render(<div suppressContentEditableWarning={true} />);
|
||||
expect(e.getAttribute('suppressContentEditableWarning')).toBe(null);
|
||||
});
|
||||
|
||||
itRenders('no suppressHydrationWarning attribute', async render => {
|
||||
const e = await render(<span suppressHydrationWarning={true} />);
|
||||
expect(e.getAttribute('suppressHydrationWarning')).toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe('inline styles', function() {
|
||||
|
@ -2623,6 +2633,36 @@ describe('ReactDOMServerIntegration', () => {
|
|||
|
||||
it('should error reconnecting different attribute values', () =>
|
||||
expectMarkupMismatch(<div id="foo" />, <div id="bar" />));
|
||||
|
||||
it('can explicitly ignore errors reconnecting different element types of children', () =>
|
||||
expectMarkupMatch(
|
||||
<div><div /></div>,
|
||||
<div suppressHydrationWarning={true}><span /></div>,
|
||||
));
|
||||
|
||||
it('can explicitly ignore errors reconnecting missing attributes', () =>
|
||||
expectMarkupMatch(
|
||||
<div id="foo" />,
|
||||
<div suppressHydrationWarning={true} />,
|
||||
));
|
||||
|
||||
it('can explicitly ignore errors reconnecting added attributes', () =>
|
||||
expectMarkupMatch(
|
||||
<div />,
|
||||
<div id="foo" suppressHydrationWarning={true} />,
|
||||
));
|
||||
|
||||
it('can explicitly ignore errors reconnecting different attribute values', () =>
|
||||
expectMarkupMatch(
|
||||
<div id="foo" />,
|
||||
<div id="bar" suppressHydrationWarning={true} />,
|
||||
));
|
||||
|
||||
it('can not deeply ignore errors reconnecting different attribute values', () =>
|
||||
expectMarkupMismatch(
|
||||
<div><div id="foo" /></div>,
|
||||
<div suppressHydrationWarning={true}><div id="bar" /></div>,
|
||||
));
|
||||
});
|
||||
|
||||
describe('inline styles', function() {
|
||||
|
@ -2661,6 +2701,18 @@ describe('ReactDOMServerIntegration', () => {
|
|||
<div style={{width: '1px', fontSize: '2px'}} />,
|
||||
<div style={{fontSize: '2px', width: '1px'}} />,
|
||||
));
|
||||
|
||||
it('can explicitly ignore errors reconnecting added style values', () =>
|
||||
expectMarkupMatch(
|
||||
<div style={{}} />,
|
||||
<div style={{width: '1px'}} suppressHydrationWarning={true} />,
|
||||
));
|
||||
|
||||
it('can explicitly ignore reconnecting different style values', () =>
|
||||
expectMarkupMatch(
|
||||
<div style={{width: '1px'}} />,
|
||||
<div style={{width: '2px'}} suppressHydrationWarning={true} />,
|
||||
));
|
||||
});
|
||||
|
||||
describe('text nodes', function() {
|
||||
|
@ -2681,6 +2733,18 @@ describe('ReactDOMServerIntegration', () => {
|
|||
<div>{'Text1'}{'Text2'}</div>,
|
||||
<div>{'Text1'}{'Text3'}</div>,
|
||||
));
|
||||
|
||||
it('can explicitly ignore reconnecting different text', () =>
|
||||
expectMarkupMatch(
|
||||
<div>Text</div>,
|
||||
<div suppressHydrationWarning={true}>Other Text</div>,
|
||||
));
|
||||
|
||||
it('can explicitly ignore reconnecting different text in two code blocks', () =>
|
||||
expectMarkupMatch(
|
||||
<div suppressHydrationWarning={true}>{'Text1'}{'Text2'}</div>,
|
||||
<div suppressHydrationWarning={true}>{'Text1'}{'Text3'}</div>,
|
||||
));
|
||||
});
|
||||
|
||||
describe('element trees and children', function() {
|
||||
|
@ -2731,6 +2795,30 @@ describe('ReactDOMServerIntegration', () => {
|
|||
|
||||
it('can distinguish an empty component from an empty text component', () =>
|
||||
expectMarkupMatch(<div><EmptyComponent /></div>, <div>{''}</div>));
|
||||
|
||||
it('can explicitly ignore reconnecting more children', () =>
|
||||
expectMarkupMatch(
|
||||
<div><div /></div>,
|
||||
<div suppressHydrationWarning={true}><div /><div /></div>,
|
||||
));
|
||||
|
||||
it('can explicitly ignore reconnecting fewer children', () =>
|
||||
expectMarkupMatch(
|
||||
<div><div /><div /></div>,
|
||||
<div suppressHydrationWarning={true}><div /></div>,
|
||||
));
|
||||
|
||||
it('can explicitly ignore reconnecting reordered children', () =>
|
||||
expectMarkupMatch(
|
||||
<div suppressHydrationWarning={true}><div /><span /></div>,
|
||||
<div suppressHydrationWarning={true}><span /><div /></div>,
|
||||
));
|
||||
|
||||
it('can not deeply ignore reconnecting reordered children', () =>
|
||||
expectMarkupMismatch(
|
||||
<div suppressHydrationWarning={true}><div><div /><span /></div></div>,
|
||||
<div suppressHydrationWarning={true}><div><span /><div /></div></div>,
|
||||
));
|
||||
});
|
||||
|
||||
// Markup Mismatches: misc
|
||||
|
@ -2739,5 +2827,14 @@ describe('ReactDOMServerIntegration', () => {
|
|||
<div dangerouslySetInnerHTML={{__html: "<span id='child1'/>"}} />,
|
||||
<div dangerouslySetInnerHTML={{__html: "<span id='child2'/>"}} />,
|
||||
));
|
||||
|
||||
it('can explicitly ignore reconnecting a div with different dangerouslySetInnerHTML', () =>
|
||||
expectMarkupMatch(
|
||||
<div dangerouslySetInnerHTML={{__html: "<span id='child1'/>"}} />,
|
||||
<div
|
||||
dangerouslySetInnerHTML={{__html: "<span id='child2'/>"}}
|
||||
suppressHydrationWarning={true}
|
||||
/>,
|
||||
));
|
||||
});
|
||||
});
|
||||
|
|
|
@ -401,6 +401,7 @@ var possibleStandardNames = {
|
|||
strokeopacity: 'strokeOpacity',
|
||||
'stroke-opacity': 'strokeOpacity',
|
||||
suppresscontenteditablewarning: 'suppressContentEditableWarning',
|
||||
suppresshydrationwarning: 'suppressHydrationWarning',
|
||||
surfacescale: 'surfaceScale',
|
||||
systemlanguage: 'systemLanguage',
|
||||
tablevalues: 'tableValues',
|
||||
|
|
|
@ -44,7 +44,13 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
|
|||
getFirstHydratableChild,
|
||||
hydrateInstance,
|
||||
hydrateTextInstance,
|
||||
didNotMatchHydratedContainerTextInstance,
|
||||
didNotMatchHydratedTextInstance,
|
||||
didNotHydrateContainerInstance,
|
||||
didNotHydrateInstance,
|
||||
// TODO: These are currently unused, see below.
|
||||
// didNotFindHydratableContainerInstance,
|
||||
// didNotFindHydratableContainerTextInstance,
|
||||
didNotFindHydratableInstance,
|
||||
didNotFindHydratableTextInstance,
|
||||
} = config;
|
||||
|
@ -57,7 +63,12 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
|
|||
getFirstHydratableChild &&
|
||||
hydrateInstance &&
|
||||
hydrateTextInstance &&
|
||||
didNotMatchHydratedContainerTextInstance &&
|
||||
didNotMatchHydratedTextInstance &&
|
||||
didNotHydrateContainerInstance &&
|
||||
didNotHydrateInstance &&
|
||||
// didNotFindHydratableContainerInstance &&
|
||||
// didNotFindHydratableContainerTextInstance &&
|
||||
didNotFindHydratableInstance &&
|
||||
didNotFindHydratableTextInstance)
|
||||
) {
|
||||
|
@ -105,10 +116,18 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
|
|||
if (__DEV__) {
|
||||
switch (returnFiber.tag) {
|
||||
case HostRoot:
|
||||
didNotHydrateInstance(returnFiber.stateNode.containerInfo, instance);
|
||||
didNotHydrateContainerInstance(
|
||||
returnFiber.stateNode.containerInfo,
|
||||
instance,
|
||||
);
|
||||
break;
|
||||
case HostComponent:
|
||||
didNotHydrateInstance(returnFiber.stateNode, instance);
|
||||
didNotHydrateInstance(
|
||||
returnFiber.type,
|
||||
returnFiber.memoizedProps,
|
||||
returnFiber.stateNode,
|
||||
instance,
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -134,32 +153,57 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
|
|||
function insertNonHydratedInstance(returnFiber: Fiber, fiber: Fiber) {
|
||||
fiber.effectTag |= Placement;
|
||||
if (__DEV__) {
|
||||
var parentInstance;
|
||||
switch (returnFiber.tag) {
|
||||
// TODO: Currently we don't warn for insertions into the root because
|
||||
// we always insert into the root in the non-hydrating case. We just
|
||||
// delete the existing content. Reenable this once we have a better
|
||||
// strategy for determining if we're hydrating or not.
|
||||
// case HostRoot:
|
||||
// parentInstance = returnFiber.stateNode.containerInfo;
|
||||
// case HostRoot: {
|
||||
// const parentContainer = returnFiber.stateNode.containerInfo;
|
||||
// switch (fiber.tag) {
|
||||
// case HostComponent:
|
||||
// const type = fiber.type;
|
||||
// const props = fiber.pendingProps;
|
||||
// didNotFindHydratableContainerInstance(parentContainer, type, props);
|
||||
// break;
|
||||
// case HostText:
|
||||
// const text = fiber.pendingProps;
|
||||
// didNotFindHydratableContainerTextInstance(parentContainer, text);
|
||||
// break;
|
||||
// }
|
||||
// break;
|
||||
case HostComponent:
|
||||
parentInstance = returnFiber.stateNode;
|
||||
// }
|
||||
case HostComponent: {
|
||||
const parentType = returnFiber.type;
|
||||
const parentProps = returnFiber.memoizedProps;
|
||||
const parentInstance = returnFiber.stateNode;
|
||||
switch (fiber.tag) {
|
||||
case HostComponent:
|
||||
const type = fiber.type;
|
||||
const props = fiber.pendingProps;
|
||||
didNotFindHydratableInstance(
|
||||
parentType,
|
||||
parentProps,
|
||||
parentInstance,
|
||||
type,
|
||||
props,
|
||||
);
|
||||
break;
|
||||
case HostText:
|
||||
const text = fiber.pendingProps;
|
||||
didNotFindHydratableTextInstance(
|
||||
parentType,
|
||||
parentProps,
|
||||
parentInstance,
|
||||
text,
|
||||
);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
switch (fiber.tag) {
|
||||
case HostComponent:
|
||||
const type = fiber.type;
|
||||
const props = fiber.pendingProps;
|
||||
didNotFindHydratableInstance(parentInstance, type, props);
|
||||
break;
|
||||
case HostText:
|
||||
const text = fiber.pendingProps;
|
||||
didNotFindHydratableTextInstance(parentInstance, text);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -243,11 +287,41 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
|
|||
|
||||
function prepareToHydrateHostTextInstance(fiber: Fiber): boolean {
|
||||
const textInstance: TI = fiber.stateNode;
|
||||
const shouldUpdate = hydrateTextInstance(
|
||||
textInstance,
|
||||
fiber.memoizedProps,
|
||||
fiber,
|
||||
);
|
||||
const textContent: string = fiber.memoizedProps;
|
||||
const shouldUpdate = hydrateTextInstance(textInstance, textContent, fiber);
|
||||
if (__DEV__) {
|
||||
if (shouldUpdate) {
|
||||
// We assume that prepareToHydrateHostTextInstance is called in a context where the
|
||||
// hydration parent is the parent host component of this host text.
|
||||
const returnFiber = hydrationParentFiber;
|
||||
if (returnFiber !== null) {
|
||||
switch (returnFiber.tag) {
|
||||
case HostRoot: {
|
||||
const parentContainer = returnFiber.stateNode.containerInfo;
|
||||
didNotMatchHydratedContainerTextInstance(
|
||||
parentContainer,
|
||||
textInstance,
|
||||
textContent,
|
||||
);
|
||||
break;
|
||||
}
|
||||
case HostComponent: {
|
||||
const parentType = returnFiber.type;
|
||||
const parentProps = returnFiber.memoizedProps;
|
||||
const parentInstance = returnFiber.stateNode;
|
||||
didNotMatchHydratedTextInstance(
|
||||
parentType,
|
||||
parentProps,
|
||||
parentInstance,
|
||||
textInstance,
|
||||
textContent,
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return shouldUpdate;
|
||||
}
|
||||
|
||||
|
|
|
@ -140,14 +140,48 @@ export type HostConfig<T, P, I, TI, PI, C, CX, PL> = {
|
|||
text: string,
|
||||
internalInstanceHandle: OpaqueHandle,
|
||||
) => boolean,
|
||||
didNotHydrateInstance?: (parentInstance: I | C, instance: I | TI) => void,
|
||||
didNotMatchHydratedContainerTextInstance?: (
|
||||
parentContainer: C,
|
||||
textInstance: TI,
|
||||
text: string,
|
||||
) => void,
|
||||
didNotMatchHydratedTextInstance?: (
|
||||
parentType: T,
|
||||
parentProps: P,
|
||||
parentInstance: I,
|
||||
textInstance: TI,
|
||||
text: string,
|
||||
) => void,
|
||||
didNotHydrateContainerInstance?: (
|
||||
parentContainer: C,
|
||||
instance: I | TI,
|
||||
) => void,
|
||||
didNotHydrateInstance?: (
|
||||
parentType: T,
|
||||
parentProps: P,
|
||||
parentInstance: I,
|
||||
instance: I | TI,
|
||||
) => void,
|
||||
didNotFindHydratableContainerInstance?: (
|
||||
parentContainer: C,
|
||||
type: T,
|
||||
props: P,
|
||||
) => void,
|
||||
didNotFindHydratableContainerTextInstance?: (
|
||||
parentContainer: C,
|
||||
text: string,
|
||||
) => void,
|
||||
didNotFindHydratableInstance?: (
|
||||
parentInstance: I | C,
|
||||
parentType: T,
|
||||
parentProps: P,
|
||||
parentInstance: I,
|
||||
type: T,
|
||||
props: P,
|
||||
) => void,
|
||||
didNotFindHydratableTextInstance?: (
|
||||
parentInstance: I | C,
|
||||
parentType: T,
|
||||
parentProps: P,
|
||||
parentInstance: I,
|
||||
text: string,
|
||||
) => void,
|
||||
|
||||
|
|
|
@ -251,6 +251,7 @@ var RESERVED_PROPS = {
|
|||
children: null,
|
||||
dangerouslySetInnerHTML: null,
|
||||
suppressContentEditableWarning: null,
|
||||
suppressHydrationWarning: null,
|
||||
};
|
||||
|
||||
function createOpenTagMarkup(
|
||||
|
|
Loading…
Reference in New Issue