mirror of
https://github.com/zebrajr/react.git
synced 2026-01-15 12:15:22 +00:00
[CS] Split Host Config Out into a Mutable or Immutable Mode (#11213)
* CS renderer Because we didn't have enough RN experiments. I want to add one more. * Split out hydration from the host config object This makes it easier to do feature detection on the configuration. * Move mutation host config to separate optional object * Refs and life-cycles should happen even in immutable mode * Unmount components even in non-mutation mode This is the same as committing deletions but instead of finding host components to delete, it only invokes componentWillUnmount and detaching of refs. * Add persistent updates API This mode will use a clone based API instead of mutating host instances. Needs implementation still. It's awkward that there can be more than one child inserted into the root. So we need a new API to create a "root" instance so that we can update it atomically. Alternatively we could keep the mutable API for containers and assume that most use cases would only have a single root. * Package up CS renderer * Fix reconciler package fixture
This commit is contained in:
committed by
GitHub
parent
339d6cb32b
commit
36a2afccc5
@@ -115,28 +115,12 @@ var NoopRenderer = ReactFiberReconciler({
|
||||
return UPDATE_SIGNAL;
|
||||
},
|
||||
|
||||
commitMount(instance: Instance, type: string, newProps: Props): void {
|
||||
// Noop
|
||||
},
|
||||
|
||||
commitUpdate(
|
||||
instance: Instance,
|
||||
updatePayload: Object,
|
||||
type: string,
|
||||
oldProps: Props,
|
||||
newProps: Props
|
||||
): void {
|
||||
instance.prop = newProps.prop;
|
||||
},
|
||||
|
||||
shouldSetTextContent(type: string, props: Props): boolean {
|
||||
return (
|
||||
typeof props.children === 'string' || typeof props.children === 'number'
|
||||
);
|
||||
},
|
||||
|
||||
resetTextContent(instance: Instance): void {},
|
||||
|
||||
shouldDeprioritizeSubtree(type: string, props: Props): boolean {
|
||||
return !!props.hidden;
|
||||
},
|
||||
@@ -155,21 +139,6 @@ var NoopRenderer = ReactFiberReconciler({
|
||||
return inst;
|
||||
},
|
||||
|
||||
commitTextUpdate(
|
||||
textInstance: TextInstance,
|
||||
oldText: string,
|
||||
newText: string
|
||||
): void {
|
||||
textInstance.text = newText;
|
||||
},
|
||||
|
||||
appendChild: appendChild,
|
||||
appendChildToContainer: appendChild,
|
||||
insertBefore: insertBefore,
|
||||
insertInContainerBefore: insertBefore,
|
||||
removeChild: removeChild,
|
||||
removeChildFromContainer: removeChild,
|
||||
|
||||
scheduleDeferredCallback(callback) {
|
||||
if (scheduledCallback) {
|
||||
throw new Error(
|
||||
@@ -183,6 +152,39 @@ var NoopRenderer = ReactFiberReconciler({
|
||||
prepareForCommit(): void {},
|
||||
|
||||
resetAfterCommit(): void {},
|
||||
|
||||
mutation: {
|
||||
commitMount(instance: Instance, type: string, newProps: Props): void {
|
||||
// Noop
|
||||
},
|
||||
|
||||
commitUpdate(
|
||||
instance: Instance,
|
||||
updatePayload: Object,
|
||||
type: string,
|
||||
oldProps: Props,
|
||||
newProps: Props
|
||||
): void {
|
||||
instance.prop = newProps.prop;
|
||||
},
|
||||
|
||||
commitTextUpdate(
|
||||
textInstance: TextInstance,
|
||||
oldText: string,
|
||||
newText: string
|
||||
): void {
|
||||
textInstance.text = newText;
|
||||
},
|
||||
|
||||
appendChild: appendChild,
|
||||
appendChildToContainer: appendChild,
|
||||
insertBefore: insertBefore,
|
||||
insertInContainerBefore: insertBefore,
|
||||
removeChild: removeChild,
|
||||
removeChildFromContainer: removeChild,
|
||||
|
||||
resetTextContent(instance: Instance): void {},
|
||||
},
|
||||
});
|
||||
|
||||
var rootContainers = new Map();
|
||||
|
||||
@@ -21,6 +21,7 @@ const Stats = require('./stats');
|
||||
const syncReactDom = require('./sync').syncReactDom;
|
||||
const syncReactNative = require('./sync').syncReactNative;
|
||||
const syncReactNativeRT = require('./sync').syncReactNativeRT;
|
||||
const syncReactNativeCS = require('./sync').syncReactNativeCS;
|
||||
const Packaging = require('./packaging');
|
||||
const Header = require('./header');
|
||||
const closure = require('rollup-plugin-closure-compiler-js');
|
||||
@@ -571,6 +572,7 @@ rimraf('build', () => {
|
||||
Packaging.createFacebookWWWBuild,
|
||||
Packaging.createReactNativeBuild,
|
||||
Packaging.createReactNativeRTBuild,
|
||||
Packaging.createReactNativeCSBuild,
|
||||
];
|
||||
for (const bundle of Bundles.bundles) {
|
||||
tasks.push(
|
||||
@@ -591,6 +593,9 @@ rimraf('build', () => {
|
||||
tasks.push(() =>
|
||||
syncReactNativeRT(join('build', 'react-native-rt'), syncFbsource)
|
||||
);
|
||||
tasks.push(() =>
|
||||
syncReactNativeCS(join('build', 'react-native-cs'), syncFbsource)
|
||||
);
|
||||
} else if (syncWww) {
|
||||
tasks.push(() => syncReactDom(join('build', 'facebook-www'), syncWww));
|
||||
}
|
||||
|
||||
@@ -298,7 +298,7 @@ const bundles = [
|
||||
useFiber: true,
|
||||
},
|
||||
|
||||
/******* React Native *******/
|
||||
/******* React Native RT *******/
|
||||
{
|
||||
babelOpts: babelOptsReact,
|
||||
bundleTypes: [RN_DEV, RN_PROD],
|
||||
@@ -332,6 +332,32 @@ const bundles = [
|
||||
useFiber: true,
|
||||
},
|
||||
|
||||
/******* React Native CS *******/
|
||||
{
|
||||
babelOpts: babelOptsReact,
|
||||
bundleTypes: [RN_DEV, RN_PROD],
|
||||
config: {
|
||||
destDir: 'build/',
|
||||
moduleName: 'ReactNativeCSFiber',
|
||||
sourceMap: false,
|
||||
},
|
||||
entry: 'src/renderers/native-cs/ReactNativeCSFiberEntry',
|
||||
externals: ['prop-types/checkPropTypes'],
|
||||
hasteName: 'ReactNativeCSFiber',
|
||||
isRenderer: true,
|
||||
label: 'native-cs-fiber',
|
||||
manglePropertiesOnProd: false,
|
||||
name: 'react-native-cs-renderer',
|
||||
paths: [
|
||||
'src/renderers/native-cs/**/*.js',
|
||||
'src/renderers/shared/**/*.js',
|
||||
|
||||
'src/ReactVersion.js',
|
||||
'src/shared/**/*.js',
|
||||
],
|
||||
useFiber: true,
|
||||
},
|
||||
|
||||
/******* React Test Renderer *******/
|
||||
{
|
||||
babelOpts: babelOptsReact,
|
||||
|
||||
@@ -33,6 +33,11 @@ const reactNativeRTSrcDependencies = [
|
||||
'src/renderers/native-rt/ReactNativeRTTypes.js',
|
||||
];
|
||||
|
||||
// these files need to be copied to the react-native-cs build
|
||||
const reactNativeCSSrcDependencies = [
|
||||
'src/renderers/native-cs/ReactNativeCSTypes.js',
|
||||
];
|
||||
|
||||
function getPackageName(name) {
|
||||
if (name.indexOf('/') !== -1) {
|
||||
return name.split('/')[0];
|
||||
@@ -81,6 +86,25 @@ function createReactNativeRTBuild() {
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
function createReactNativeCSBuild() {
|
||||
// create the react-native-cs folder for FB bundles
|
||||
fs.mkdirSync(join('build', 'react-native-cs'));
|
||||
// create the react-native-cs shims folder for FB shims
|
||||
fs.mkdirSync(join('build', 'react-native-cs', 'shims'));
|
||||
|
||||
const to = join('build', 'react-native-cs', 'shims');
|
||||
|
||||
let promises = [];
|
||||
// we also need to copy over some specific files from src
|
||||
// defined in reactNativeCSSrcDependencies
|
||||
for (const srcDependency of reactNativeCSSrcDependencies) {
|
||||
promises.push(
|
||||
asyncCopyTo(resolve(srcDependency), join(to, basename(srcDependency)))
|
||||
);
|
||||
}
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
function createFacebookWWWBuild() {
|
||||
// create the facebookWWW folder for FB bundles
|
||||
fs.mkdirSync(join('build', facebookWWW));
|
||||
@@ -191,4 +215,5 @@ module.exports = {
|
||||
createFacebookWWWBuild,
|
||||
createReactNativeBuild,
|
||||
createReactNativeRTBuild,
|
||||
createReactNativeCSBuild,
|
||||
};
|
||||
|
||||
@@ -25,28 +25,28 @@
|
||||
"gzip": 6703
|
||||
},
|
||||
"react-dom.development.js (UMD_DEV)": {
|
||||
"size": 630418,
|
||||
"gzip": 145239
|
||||
"size": 625837,
|
||||
"gzip": 144320
|
||||
},
|
||||
"react-dom.production.min.js (UMD_PROD)": {
|
||||
"size": 101638,
|
||||
"gzip": 32128
|
||||
"size": 100866,
|
||||
"gzip": 31848
|
||||
},
|
||||
"react-dom.development.js (NODE_DEV)": {
|
||||
"size": 592683,
|
||||
"gzip": 136496
|
||||
"size": 588106,
|
||||
"gzip": 135609
|
||||
},
|
||||
"react-dom.production.min.js (NODE_PROD)": {
|
||||
"size": 106507,
|
||||
"gzip": 33538
|
||||
"size": 105343,
|
||||
"gzip": 33129
|
||||
},
|
||||
"ReactDOMFiber-dev.js (FB_DEV)": {
|
||||
"size": 589582,
|
||||
"gzip": 135915
|
||||
"size": 584995,
|
||||
"gzip": 135013
|
||||
},
|
||||
"ReactDOMFiber-prod.js (FB_PROD)": {
|
||||
"size": 419983,
|
||||
"gzip": 93676
|
||||
"size": 414881,
|
||||
"gzip": 92663
|
||||
},
|
||||
"react-dom-test-utils.development.js (NODE_DEV)": {
|
||||
"size": 41660,
|
||||
@@ -113,44 +113,44 @@
|
||||
"gzip": 6214
|
||||
},
|
||||
"react-art.development.js (UMD_DEV)": {
|
||||
"size": 376896,
|
||||
"gzip": 83318
|
||||
"size": 372576,
|
||||
"gzip": 82452
|
||||
},
|
||||
"react-art.production.min.js (UMD_PROD)": {
|
||||
"size": 83700,
|
||||
"gzip": 25995
|
||||
"size": 83057,
|
||||
"gzip": 25828
|
||||
},
|
||||
"react-art.development.js (NODE_DEV)": {
|
||||
"size": 301201,
|
||||
"gzip": 64095
|
||||
"size": 296909,
|
||||
"gzip": 63228
|
||||
},
|
||||
"react-art.production.min.js (NODE_PROD)": {
|
||||
"size": 53531,
|
||||
"gzip": 16898
|
||||
"size": 52508,
|
||||
"gzip": 16427
|
||||
},
|
||||
"ReactARTFiber-dev.js (FB_DEV)": {
|
||||
"size": 300073,
|
||||
"gzip": 64131
|
||||
"size": 295771,
|
||||
"gzip": 63258
|
||||
},
|
||||
"ReactARTFiber-prod.js (FB_PROD)": {
|
||||
"size": 224585,
|
||||
"gzip": 46566
|
||||
"size": 219800,
|
||||
"gzip": 45628
|
||||
},
|
||||
"ReactNativeFiber-dev.js (RN_DEV)": {
|
||||
"size": 283095,
|
||||
"gzip": 49176
|
||||
"size": 279764,
|
||||
"gzip": 48665
|
||||
},
|
||||
"ReactNativeFiber-prod.js (RN_PROD)": {
|
||||
"size": 221913,
|
||||
"gzip": 38509
|
||||
"size": 218506,
|
||||
"gzip": 37873
|
||||
},
|
||||
"react-test-renderer.development.js (NODE_DEV)": {
|
||||
"size": 304971,
|
||||
"gzip": 64484
|
||||
"size": 300619,
|
||||
"gzip": 63624
|
||||
},
|
||||
"ReactTestRendererFiber-dev.js (FB_DEV)": {
|
||||
"size": 303833,
|
||||
"gzip": 64527
|
||||
"size": 299471,
|
||||
"gzip": 63657
|
||||
},
|
||||
"react-test-renderer-shallow.development.js (NODE_DEV)": {
|
||||
"size": 9215,
|
||||
@@ -161,8 +161,8 @@
|
||||
"gzip": 2221
|
||||
},
|
||||
"react-noop-renderer.development.js (NODE_DEV)": {
|
||||
"size": 292571,
|
||||
"gzip": 61440
|
||||
"size": 288214,
|
||||
"gzip": 60549
|
||||
},
|
||||
"react-dom-server.development.js (UMD_DEV)": {
|
||||
"size": 120897,
|
||||
@@ -189,16 +189,16 @@
|
||||
"gzip": 7520
|
||||
},
|
||||
"ReactNativeRTFiber-dev.js (RN_DEV)": {
|
||||
"size": 215098,
|
||||
"gzip": 36673
|
||||
"size": 211687,
|
||||
"gzip": 36145
|
||||
},
|
||||
"ReactNativeRTFiber-prod.js (RN_PROD)": {
|
||||
"size": 163687,
|
||||
"gzip": 27527
|
||||
"size": 160200,
|
||||
"gzip": 26880
|
||||
},
|
||||
"react-test-renderer.production.min.js (NODE_PROD)": {
|
||||
"size": 55085,
|
||||
"gzip": 17135
|
||||
"size": 54076,
|
||||
"gzip": 16776
|
||||
},
|
||||
"react-test-renderer-shallow.production.min.js (NODE_PROD)": {
|
||||
"size": 4536,
|
||||
@@ -209,12 +209,20 @@
|
||||
"gzip": 4241
|
||||
},
|
||||
"react-reconciler.development.js (NODE_DEV)": {
|
||||
"size": 279927,
|
||||
"gzip": 58576
|
||||
"size": 275518,
|
||||
"gzip": 57698
|
||||
},
|
||||
"react-reconciler.production.min.js (NODE_PROD)": {
|
||||
"size": 38630,
|
||||
"gzip": 12165
|
||||
"size": 37979,
|
||||
"gzip": 11842
|
||||
},
|
||||
"ReactNativeCSFiber-dev.js (RN_DEV)": {
|
||||
"size": 204077,
|
||||
"gzip": 34318
|
||||
},
|
||||
"ReactNativeCSFiber-prod.js (RN_PROD)": {
|
||||
"size": 155097,
|
||||
"gzip": 25642
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -388,20 +388,6 @@ class Text extends React.Component {
|
||||
/** ART Renderer */
|
||||
|
||||
const ARTRenderer = ReactFiberReconciler({
|
||||
appendChild(parentInstance, child) {
|
||||
if (child.parentNode === parentInstance) {
|
||||
child.eject();
|
||||
}
|
||||
child.inject(parentInstance);
|
||||
},
|
||||
|
||||
appendChildToContainer(parentInstance, child) {
|
||||
if (child.parentNode === parentInstance) {
|
||||
child.eject();
|
||||
}
|
||||
child.inject(parentInstance);
|
||||
},
|
||||
|
||||
appendInitialChild(parentInstance, child) {
|
||||
if (typeof child === 'string') {
|
||||
// Noop for string children of Text (eg <Text>{'foo'}{'bar'}</Text>)
|
||||
@@ -412,18 +398,6 @@ const ARTRenderer = ReactFiberReconciler({
|
||||
child.inject(parentInstance);
|
||||
},
|
||||
|
||||
commitTextUpdate(textInstance, oldText, newText) {
|
||||
// Noop
|
||||
},
|
||||
|
||||
commitMount(instance, type, newProps) {
|
||||
// Noop
|
||||
},
|
||||
|
||||
commitUpdate(instance, updatePayload, type, oldProps, newProps) {
|
||||
instance._applyProps(instance, newProps, oldProps);
|
||||
},
|
||||
|
||||
createInstance(type, props, internalInstanceHandle) {
|
||||
let instance;
|
||||
|
||||
@@ -470,22 +444,6 @@ const ARTRenderer = ReactFiberReconciler({
|
||||
return instance;
|
||||
},
|
||||
|
||||
insertBefore(parentInstance, child, beforeChild) {
|
||||
invariant(
|
||||
child !== beforeChild,
|
||||
'ReactART: Can not insert node before itself',
|
||||
);
|
||||
child.injectBefore(beforeChild);
|
||||
},
|
||||
|
||||
insertInContainerBefore(parentInstance, child, beforeChild) {
|
||||
invariant(
|
||||
child !== beforeChild,
|
||||
'ReactART: Can not insert node before itself',
|
||||
);
|
||||
child.injectBefore(beforeChild);
|
||||
},
|
||||
|
||||
prepareForCommit() {
|
||||
// Noop
|
||||
},
|
||||
@@ -494,16 +452,6 @@ const ARTRenderer = ReactFiberReconciler({
|
||||
return UPDATE_SIGNAL;
|
||||
},
|
||||
|
||||
removeChild(parentInstance, child) {
|
||||
destroyEventListeners(child);
|
||||
child.eject();
|
||||
},
|
||||
|
||||
removeChildFromContainer(parentInstance, child) {
|
||||
destroyEventListeners(child);
|
||||
child.eject();
|
||||
},
|
||||
|
||||
resetAfterCommit() {
|
||||
// Noop
|
||||
},
|
||||
@@ -535,6 +483,60 @@ const ARTRenderer = ReactFiberReconciler({
|
||||
now: ReactDOMFrameScheduling.now,
|
||||
|
||||
useSyncScheduling: true,
|
||||
|
||||
mutation: {
|
||||
appendChild(parentInstance, child) {
|
||||
if (child.parentNode === parentInstance) {
|
||||
child.eject();
|
||||
}
|
||||
child.inject(parentInstance);
|
||||
},
|
||||
|
||||
appendChildToContainer(parentInstance, child) {
|
||||
if (child.parentNode === parentInstance) {
|
||||
child.eject();
|
||||
}
|
||||
child.inject(parentInstance);
|
||||
},
|
||||
|
||||
insertBefore(parentInstance, child, beforeChild) {
|
||||
invariant(
|
||||
child !== beforeChild,
|
||||
'ReactART: Can not insert node before itself',
|
||||
);
|
||||
child.injectBefore(beforeChild);
|
||||
},
|
||||
|
||||
insertInContainerBefore(parentInstance, child, beforeChild) {
|
||||
invariant(
|
||||
child !== beforeChild,
|
||||
'ReactART: Can not insert node before itself',
|
||||
);
|
||||
child.injectBefore(beforeChild);
|
||||
},
|
||||
|
||||
removeChild(parentInstance, child) {
|
||||
destroyEventListeners(child);
|
||||
child.eject();
|
||||
},
|
||||
|
||||
removeChildFromContainer(parentInstance, child) {
|
||||
destroyEventListeners(child);
|
||||
child.eject();
|
||||
},
|
||||
|
||||
commitTextUpdate(textInstance, oldText, newText) {
|
||||
// Noop
|
||||
},
|
||||
|
||||
commitMount(instance, type, newProps) {
|
||||
// Noop
|
||||
},
|
||||
|
||||
commitUpdate(instance, updatePayload, type, oldProps, newProps) {
|
||||
instance._applyProps(instance, newProps, oldProps);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/** API */
|
||||
|
||||
@@ -317,34 +317,6 @@ var DOMRenderer = ReactFiberReconciler({
|
||||
);
|
||||
},
|
||||
|
||||
commitMount(
|
||||
domElement: Instance,
|
||||
type: string,
|
||||
newProps: Props,
|
||||
internalInstanceHandle: Object,
|
||||
): void {
|
||||
((domElement: any):
|
||||
| HTMLButtonElement
|
||||
| HTMLInputElement
|
||||
| HTMLSelectElement
|
||||
| HTMLTextAreaElement).focus();
|
||||
},
|
||||
|
||||
commitUpdate(
|
||||
domElement: Instance,
|
||||
updatePayload: Array<mixed>,
|
||||
type: string,
|
||||
oldProps: Props,
|
||||
newProps: Props,
|
||||
internalInstanceHandle: Object,
|
||||
): void {
|
||||
// Update the props handle so that we know which props are the ones with
|
||||
// with current event handlers.
|
||||
updateFiberProps(domElement, newProps);
|
||||
// Apply the diff to the DOM node.
|
||||
updateProperties(domElement, updatePayload, type, oldProps, newProps);
|
||||
},
|
||||
|
||||
shouldSetTextContent(type: string, props: Props): boolean {
|
||||
return (
|
||||
type === 'textarea' ||
|
||||
@@ -356,10 +328,6 @@ var DOMRenderer = ReactFiberReconciler({
|
||||
);
|
||||
},
|
||||
|
||||
resetTextContent(domElement: Instance): void {
|
||||
domElement.textContent = '';
|
||||
},
|
||||
|
||||
shouldDeprioritizeSubtree(type: string, props: Props): boolean {
|
||||
return !!props.hidden;
|
||||
},
|
||||
@@ -379,245 +347,287 @@ var DOMRenderer = ReactFiberReconciler({
|
||||
return textNode;
|
||||
},
|
||||
|
||||
commitTextUpdate(
|
||||
textInstance: TextInstance,
|
||||
oldText: string,
|
||||
newText: string,
|
||||
): void {
|
||||
textInstance.nodeValue = newText;
|
||||
},
|
||||
|
||||
appendChild(parentInstance: Instance, child: Instance | TextInstance): void {
|
||||
parentInstance.appendChild(child);
|
||||
},
|
||||
|
||||
appendChildToContainer(
|
||||
container: Container,
|
||||
child: Instance | TextInstance,
|
||||
): void {
|
||||
if (container.nodeType === COMMENT_NODE) {
|
||||
(container.parentNode: any).insertBefore(child, container);
|
||||
} else {
|
||||
container.appendChild(child);
|
||||
}
|
||||
},
|
||||
|
||||
insertBefore(
|
||||
parentInstance: Instance,
|
||||
child: Instance | TextInstance,
|
||||
beforeChild: Instance | TextInstance,
|
||||
): void {
|
||||
parentInstance.insertBefore(child, beforeChild);
|
||||
},
|
||||
|
||||
insertInContainerBefore(
|
||||
container: Container,
|
||||
child: Instance | TextInstance,
|
||||
beforeChild: Instance | TextInstance,
|
||||
): void {
|
||||
if (container.nodeType === COMMENT_NODE) {
|
||||
(container.parentNode: any).insertBefore(child, beforeChild);
|
||||
} else {
|
||||
container.insertBefore(child, beforeChild);
|
||||
}
|
||||
},
|
||||
|
||||
removeChild(parentInstance: Instance, child: Instance | TextInstance): void {
|
||||
parentInstance.removeChild(child);
|
||||
},
|
||||
|
||||
removeChildFromContainer(
|
||||
container: Container,
|
||||
child: Instance | TextInstance,
|
||||
): void {
|
||||
if (container.nodeType === COMMENT_NODE) {
|
||||
(container.parentNode: any).removeChild(child);
|
||||
} else {
|
||||
container.removeChild(child);
|
||||
}
|
||||
},
|
||||
|
||||
now: ReactDOMFrameScheduling.now,
|
||||
|
||||
canHydrateInstance(
|
||||
instance: Instance | TextInstance,
|
||||
type: string,
|
||||
props: Props,
|
||||
): boolean {
|
||||
return (
|
||||
instance.nodeType === ELEMENT_NODE &&
|
||||
type.toLowerCase() === instance.nodeName.toLowerCase()
|
||||
);
|
||||
},
|
||||
mutation: {
|
||||
commitMount(
|
||||
domElement: Instance,
|
||||
type: string,
|
||||
newProps: Props,
|
||||
internalInstanceHandle: Object,
|
||||
): void {
|
||||
((domElement: any):
|
||||
| HTMLButtonElement
|
||||
| HTMLInputElement
|
||||
| HTMLSelectElement
|
||||
| HTMLTextAreaElement).focus();
|
||||
},
|
||||
|
||||
canHydrateTextInstance(
|
||||
instance: Instance | TextInstance,
|
||||
text: string,
|
||||
): boolean {
|
||||
if (text === '') {
|
||||
// Empty strings are not parsed by HTML so there won't be a correct match here.
|
||||
return false;
|
||||
}
|
||||
return instance.nodeType === TEXT_NODE;
|
||||
},
|
||||
commitUpdate(
|
||||
domElement: Instance,
|
||||
updatePayload: Array<mixed>,
|
||||
type: string,
|
||||
oldProps: Props,
|
||||
newProps: Props,
|
||||
internalInstanceHandle: Object,
|
||||
): void {
|
||||
// Update the props handle so that we know which props are the ones with
|
||||
// with current event handlers.
|
||||
updateFiberProps(domElement, newProps);
|
||||
// Apply the diff to the DOM node.
|
||||
updateProperties(domElement, updatePayload, type, oldProps, newProps);
|
||||
},
|
||||
|
||||
getNextHydratableSibling(
|
||||
instance: Instance | TextInstance,
|
||||
): null | Instance | TextInstance {
|
||||
let node = instance.nextSibling;
|
||||
// Skip non-hydratable nodes.
|
||||
while (
|
||||
node &&
|
||||
node.nodeType !== ELEMENT_NODE &&
|
||||
node.nodeType !== TEXT_NODE
|
||||
) {
|
||||
node = node.nextSibling;
|
||||
}
|
||||
return (node: any);
|
||||
},
|
||||
resetTextContent(domElement: Instance): void {
|
||||
domElement.textContent = '';
|
||||
},
|
||||
|
||||
getFirstHydratableChild(
|
||||
parentInstance: Container | Instance,
|
||||
): null | Instance | TextInstance {
|
||||
let next = parentInstance.firstChild;
|
||||
// Skip non-hydratable nodes.
|
||||
while (
|
||||
next &&
|
||||
next.nodeType !== ELEMENT_NODE &&
|
||||
next.nodeType !== TEXT_NODE
|
||||
) {
|
||||
next = next.nextSibling;
|
||||
}
|
||||
return (next: any);
|
||||
},
|
||||
commitTextUpdate(
|
||||
textInstance: TextInstance,
|
||||
oldText: string,
|
||||
newText: string,
|
||||
): void {
|
||||
textInstance.nodeValue = newText;
|
||||
},
|
||||
|
||||
hydrateInstance(
|
||||
instance: Instance,
|
||||
type: string,
|
||||
props: Props,
|
||||
rootContainerInstance: Container,
|
||||
hostContext: HostContext,
|
||||
internalInstanceHandle: Object,
|
||||
): null | Array<mixed> {
|
||||
precacheFiberNode(internalInstanceHandle, instance);
|
||||
// TODO: Possibly defer this until the commit phase where all the events
|
||||
// get attached.
|
||||
updateFiberProps(instance, props);
|
||||
let parentNamespace: string;
|
||||
if (__DEV__) {
|
||||
const hostContextDev = ((hostContext: any): HostContextDev);
|
||||
parentNamespace = hostContextDev.namespace;
|
||||
} else {
|
||||
parentNamespace = ((hostContext: any): HostContextProd);
|
||||
}
|
||||
return diffHydratedProperties(
|
||||
instance,
|
||||
type,
|
||||
props,
|
||||
parentNamespace,
|
||||
rootContainerInstance,
|
||||
);
|
||||
},
|
||||
appendChild(
|
||||
parentInstance: Instance,
|
||||
child: Instance | TextInstance,
|
||||
): void {
|
||||
parentInstance.appendChild(child);
|
||||
},
|
||||
|
||||
hydrateTextInstance(
|
||||
textInstance: TextInstance,
|
||||
text: string,
|
||||
internalInstanceHandle: Object,
|
||||
): boolean {
|
||||
precacheFiberNode(internalInstanceHandle, textInstance);
|
||||
return diffHydratedText(textInstance, text);
|
||||
},
|
||||
|
||||
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 (__DEV__) {
|
||||
if (instance.nodeType === 1) {
|
||||
warnForDeletedHydratableElement(parentContainer, (instance: any));
|
||||
appendChildToContainer(
|
||||
container: Container,
|
||||
child: Instance | TextInstance,
|
||||
): void {
|
||||
if (container.nodeType === COMMENT_NODE) {
|
||||
(container.parentNode: any).insertBefore(child, container);
|
||||
} else {
|
||||
warnForDeletedHydratableText(parentContainer, (instance: any));
|
||||
container.appendChild(child);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
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));
|
||||
insertBefore(
|
||||
parentInstance: Instance,
|
||||
child: Instance | TextInstance,
|
||||
beforeChild: Instance | TextInstance,
|
||||
): void {
|
||||
parentInstance.insertBefore(child, beforeChild);
|
||||
},
|
||||
|
||||
insertInContainerBefore(
|
||||
container: Container,
|
||||
child: Instance | TextInstance,
|
||||
beforeChild: Instance | TextInstance,
|
||||
): void {
|
||||
if (container.nodeType === COMMENT_NODE) {
|
||||
(container.parentNode: any).insertBefore(child, beforeChild);
|
||||
} else {
|
||||
warnForDeletedHydratableText(parentInstance, (instance: any));
|
||||
container.insertBefore(child, beforeChild);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
removeChild(
|
||||
parentInstance: Instance,
|
||||
child: Instance | TextInstance,
|
||||
): void {
|
||||
parentInstance.removeChild(child);
|
||||
},
|
||||
|
||||
removeChildFromContainer(
|
||||
container: Container,
|
||||
child: Instance | TextInstance,
|
||||
): void {
|
||||
if (container.nodeType === COMMENT_NODE) {
|
||||
(container.parentNode: any).removeChild(child);
|
||||
} else {
|
||||
container.removeChild(child);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
didNotFindHydratableContainerInstance(
|
||||
parentContainer: Container,
|
||||
type: string,
|
||||
props: Props,
|
||||
) {
|
||||
if (__DEV__) {
|
||||
warnForInsertedHydratedElement(parentContainer, type, props);
|
||||
}
|
||||
},
|
||||
hydration: {
|
||||
canHydrateInstance(
|
||||
instance: Instance | TextInstance,
|
||||
type: string,
|
||||
props: Props,
|
||||
): boolean {
|
||||
return (
|
||||
instance.nodeType === ELEMENT_NODE &&
|
||||
type.toLowerCase() === instance.nodeName.toLowerCase()
|
||||
);
|
||||
},
|
||||
|
||||
didNotFindHydratableContainerTextInstance(
|
||||
parentContainer: Container,
|
||||
text: string,
|
||||
) {
|
||||
if (__DEV__) {
|
||||
warnForInsertedHydratedText(parentContainer, text);
|
||||
}
|
||||
},
|
||||
canHydrateTextInstance(
|
||||
instance: Instance | TextInstance,
|
||||
text: string,
|
||||
): boolean {
|
||||
if (text === '') {
|
||||
// Empty strings are not parsed by HTML so there won't be a correct match here.
|
||||
return false;
|
||||
}
|
||||
return instance.nodeType === TEXT_NODE;
|
||||
},
|
||||
|
||||
didNotFindHydratableInstance(
|
||||
parentType: string,
|
||||
parentProps: Props,
|
||||
parentInstance: Instance,
|
||||
type: string,
|
||||
props: Props,
|
||||
) {
|
||||
if (__DEV__ && parentProps[SUPPRESS_HYDRATION_WARNING] !== true) {
|
||||
warnForInsertedHydratedElement(parentInstance, type, props);
|
||||
}
|
||||
},
|
||||
getNextHydratableSibling(
|
||||
instance: Instance | TextInstance,
|
||||
): null | Instance | TextInstance {
|
||||
let node = instance.nextSibling;
|
||||
// Skip non-hydratable nodes.
|
||||
while (
|
||||
node &&
|
||||
node.nodeType !== ELEMENT_NODE &&
|
||||
node.nodeType !== TEXT_NODE
|
||||
) {
|
||||
node = node.nextSibling;
|
||||
}
|
||||
return (node: any);
|
||||
},
|
||||
|
||||
didNotFindHydratableTextInstance(
|
||||
parentType: string,
|
||||
parentProps: Props,
|
||||
parentInstance: Instance,
|
||||
text: string,
|
||||
) {
|
||||
if (__DEV__ && parentProps[SUPPRESS_HYDRATION_WARNING] !== true) {
|
||||
warnForInsertedHydratedText(parentInstance, text);
|
||||
}
|
||||
getFirstHydratableChild(
|
||||
parentInstance: Container | Instance,
|
||||
): null | Instance | TextInstance {
|
||||
let next = parentInstance.firstChild;
|
||||
// Skip non-hydratable nodes.
|
||||
while (
|
||||
next &&
|
||||
next.nodeType !== ELEMENT_NODE &&
|
||||
next.nodeType !== TEXT_NODE
|
||||
) {
|
||||
next = next.nextSibling;
|
||||
}
|
||||
return (next: any);
|
||||
},
|
||||
|
||||
hydrateInstance(
|
||||
instance: Instance,
|
||||
type: string,
|
||||
props: Props,
|
||||
rootContainerInstance: Container,
|
||||
hostContext: HostContext,
|
||||
internalInstanceHandle: Object,
|
||||
): null | Array<mixed> {
|
||||
precacheFiberNode(internalInstanceHandle, instance);
|
||||
// TODO: Possibly defer this until the commit phase where all the events
|
||||
// get attached.
|
||||
updateFiberProps(instance, props);
|
||||
let parentNamespace: string;
|
||||
if (__DEV__) {
|
||||
const hostContextDev = ((hostContext: any): HostContextDev);
|
||||
parentNamespace = hostContextDev.namespace;
|
||||
} else {
|
||||
parentNamespace = ((hostContext: any): HostContextProd);
|
||||
}
|
||||
return diffHydratedProperties(
|
||||
instance,
|
||||
type,
|
||||
props,
|
||||
parentNamespace,
|
||||
rootContainerInstance,
|
||||
);
|
||||
},
|
||||
|
||||
hydrateTextInstance(
|
||||
textInstance: TextInstance,
|
||||
text: string,
|
||||
internalInstanceHandle: Object,
|
||||
): boolean {
|
||||
precacheFiberNode(internalInstanceHandle, textInstance);
|
||||
return diffHydratedText(textInstance, text);
|
||||
},
|
||||
|
||||
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 (__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(
|
||||
parentType: string,
|
||||
parentProps: Props,
|
||||
parentInstance: Instance,
|
||||
type: string,
|
||||
props: Props,
|
||||
) {
|
||||
if (__DEV__ && parentProps[SUPPRESS_HYDRATION_WARNING] !== true) {
|
||||
warnForInsertedHydratedElement(parentInstance, type, props);
|
||||
}
|
||||
},
|
||||
|
||||
didNotFindHydratableTextInstance(
|
||||
parentType: string,
|
||||
parentProps: Props,
|
||||
parentInstance: Instance,
|
||||
text: string,
|
||||
) {
|
||||
if (__DEV__ && parentProps[SUPPRESS_HYDRATION_WARNING] !== true) {
|
||||
warnForInsertedHydratedText(parentInstance, text);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
scheduleDeferredCallback: ReactDOMFrameScheduling.rIC,
|
||||
|
||||
228
src/renderers/native-cs/ReactNativeCSFiberEntry.js
Normal file
228
src/renderers/native-cs/ReactNativeCSFiberEntry.js
Normal file
@@ -0,0 +1,228 @@
|
||||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @providesModule ReactNativeCSFiberEntry
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const ReactGenericBatching = require('ReactGenericBatching');
|
||||
const ReactVersion = require('ReactVersion');
|
||||
|
||||
const {injectInternals} = require('ReactFiberDevToolsHook');
|
||||
|
||||
import type {ReactNativeCSType} from 'ReactNativeCSTypes';
|
||||
|
||||
const ReactFiberReconciler = require('ReactFiberReconciler');
|
||||
|
||||
const emptyObject = require('fbjs/lib/emptyObject');
|
||||
|
||||
export type Container = number;
|
||||
export type Instance = number;
|
||||
export type Props = Object;
|
||||
export type TextInstance = number;
|
||||
|
||||
function processProps(instance: number, props: Props): Object {
|
||||
const propsPayload = {};
|
||||
for (var key in props) {
|
||||
if (key === 'children') {
|
||||
// Skip special case.
|
||||
continue;
|
||||
}
|
||||
var value = props[key];
|
||||
if (typeof value === 'function') {
|
||||
value = {
|
||||
style: 'rt-event',
|
||||
event: key,
|
||||
tag: instance,
|
||||
};
|
||||
}
|
||||
propsPayload[key] = value;
|
||||
}
|
||||
return propsPayload;
|
||||
}
|
||||
|
||||
function arePropsEqual(oldProps: Props, newProps: Props): boolean {
|
||||
var key;
|
||||
for (key in newProps) {
|
||||
if (key === 'children') {
|
||||
// Skip special case.
|
||||
continue;
|
||||
}
|
||||
if (newProps[key] !== oldProps[key]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (key in oldProps) {
|
||||
if (key === 'children') {
|
||||
// Skip special case.
|
||||
continue;
|
||||
}
|
||||
if (!(key in newProps)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const ReactNativeCSFiberRenderer = ReactFiberReconciler({
|
||||
appendInitialChild(
|
||||
parentInstance: Instance,
|
||||
child: Instance | TextInstance,
|
||||
): void {},
|
||||
|
||||
createInstance(
|
||||
type: string,
|
||||
props: Props,
|
||||
rootContainerInstance: Container,
|
||||
hostContext: {},
|
||||
internalInstanceHandle: Object,
|
||||
): Instance {
|
||||
return 0;
|
||||
},
|
||||
|
||||
createTextInstance(
|
||||
text: string,
|
||||
rootContainerInstance: Container,
|
||||
hostContext: {},
|
||||
internalInstanceHandle: Object,
|
||||
): TextInstance {
|
||||
return 0;
|
||||
},
|
||||
|
||||
finalizeInitialChildren(
|
||||
parentInstance: Instance,
|
||||
type: string,
|
||||
props: Props,
|
||||
rootContainerInstance: Container,
|
||||
): boolean {
|
||||
return false;
|
||||
},
|
||||
|
||||
getRootHostContext(): {} {
|
||||
return emptyObject;
|
||||
},
|
||||
|
||||
getChildHostContext(): {} {
|
||||
return emptyObject;
|
||||
},
|
||||
|
||||
getPublicInstance(instance) {
|
||||
return instance;
|
||||
},
|
||||
|
||||
prepareForCommit(): void {},
|
||||
|
||||
prepareUpdate(
|
||||
instance: Instance,
|
||||
type: string,
|
||||
oldProps: Props,
|
||||
newProps: Props,
|
||||
rootContainerInstance: Container,
|
||||
hostContext: {},
|
||||
): null | Object {
|
||||
if (arePropsEqual(oldProps, newProps)) {
|
||||
return null;
|
||||
}
|
||||
return processProps(instance, newProps);
|
||||
},
|
||||
|
||||
resetAfterCommit(): void {},
|
||||
|
||||
shouldDeprioritizeSubtree(type: string, props: Props): boolean {
|
||||
return false;
|
||||
},
|
||||
|
||||
scheduleDeferredCallback: global.requestIdleCallback,
|
||||
|
||||
shouldSetTextContent(type: string, props: Props): boolean {
|
||||
// TODO: Figure out when we should allow text content.
|
||||
return false;
|
||||
},
|
||||
|
||||
useSyncScheduling: true,
|
||||
|
||||
now(): number {
|
||||
// TODO: Enable expiration by implementing this method.
|
||||
return 0;
|
||||
},
|
||||
|
||||
persistence: {
|
||||
cloneInstance(
|
||||
instance: Instance,
|
||||
updatePayload: Object,
|
||||
type: string,
|
||||
oldProps: Props,
|
||||
newProps: Props,
|
||||
internalInstanceHandle: Object,
|
||||
keepChildren: boolean,
|
||||
): Instance {
|
||||
return 0;
|
||||
},
|
||||
tryToReuseInstance(
|
||||
instance: Instance,
|
||||
updatePayload: Object,
|
||||
type: string,
|
||||
oldProps: Props,
|
||||
newProps: Props,
|
||||
internalInstanceHandle: Object,
|
||||
keepChildren: boolean,
|
||||
): Instance {
|
||||
return 0;
|
||||
},
|
||||
|
||||
createRootInstance(
|
||||
rootContainerInstance: Container,
|
||||
hostContext: {},
|
||||
): Instance {
|
||||
return 123;
|
||||
},
|
||||
commitRootInstance(rootInstance: Instance): void {},
|
||||
},
|
||||
});
|
||||
|
||||
const roots = new Map();
|
||||
|
||||
const ReactNativeCSFiber: ReactNativeCSType = {
|
||||
render(element: React$Element<any>, containerTag: any, callback: ?Function) {
|
||||
let root = roots.get(containerTag);
|
||||
|
||||
if (!root) {
|
||||
// TODO (bvaughn): If we decide to keep the wrapper component,
|
||||
// We could create a wrapper for containerTag as well to reduce special casing.
|
||||
root = ReactNativeCSFiberRenderer.createContainer(containerTag);
|
||||
roots.set(containerTag, root);
|
||||
}
|
||||
ReactNativeCSFiberRenderer.updateContainer(element, root, null, callback);
|
||||
|
||||
return ReactNativeCSFiberRenderer.getPublicRootInstance(root);
|
||||
},
|
||||
|
||||
unmountComponentAtNode(containerTag: number) {
|
||||
const root = roots.get(containerTag);
|
||||
if (root) {
|
||||
// TODO: Is it safe to reset this now or should I wait since this unmount could be deferred?
|
||||
ReactNativeCSFiberRenderer.updateContainer(null, root, null, () => {
|
||||
roots.delete(containerTag);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
unstable_batchedUpdates: ReactGenericBatching.batchedUpdates,
|
||||
|
||||
flushSync: ReactNativeCSFiberRenderer.flushSync,
|
||||
};
|
||||
|
||||
injectInternals({
|
||||
findHostInstanceByFiber: ReactNativeCSFiberRenderer.findHostInstance,
|
||||
// This is an enum because we may add more (e.g. profiler build)
|
||||
bundleType: __DEV__ ? 1 : 0,
|
||||
version: ReactVersion,
|
||||
rendererPackageName: 'react-native-cs',
|
||||
});
|
||||
|
||||
module.exports = ReactNativeCSFiber;
|
||||
24
src/renderers/native-cs/ReactNativeCSTypes.js
Normal file
24
src/renderers/native-cs/ReactNativeCSTypes.js
Normal file
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @providesModule ReactNativeCSTypes
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Flat CS renderer bundles are too big for Flow to parse efficiently.
|
||||
* Provide minimal Flow typing for the high-level RN API and call it a day.
|
||||
*/
|
||||
export type ReactNativeCSType = {
|
||||
render(
|
||||
element: React$Element<any>,
|
||||
containerTag: any,
|
||||
callback: ?Function,
|
||||
): any,
|
||||
unmountComponentAtNode(containerTag: number): any,
|
||||
unstable_batchedUpdates: any, // TODO (bvaughn) Add types
|
||||
};
|
||||
27
src/renderers/native-cs/__tests__/ReactNativeCS-test.js
Normal file
27
src/renderers/native-cs/__tests__/ReactNativeCS-test.js
Normal file
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @emails react-core
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var React;
|
||||
var ReactNativeCS;
|
||||
|
||||
describe('ReactNativeCS', () => {
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
|
||||
React = require('react');
|
||||
ReactNativeCS = require('ReactNativeCSFiberEntry');
|
||||
});
|
||||
|
||||
it('should be able to create and render a native component', () => {
|
||||
const RCTView = 'View';
|
||||
ReactNativeCS.render(<RCTView foo="test" />, 1);
|
||||
});
|
||||
});
|
||||
@@ -69,17 +69,6 @@ function arePropsEqual(oldProps: Props, newProps: Props): boolean {
|
||||
}
|
||||
|
||||
const NativeRTRenderer = ReactFiberReconciler({
|
||||
appendChild(parentInstance: Instance, child: Instance | TextInstance): void {
|
||||
RTManager.appendChild(parentInstance, child);
|
||||
},
|
||||
|
||||
appendChildToContainer(
|
||||
parentInstance: Container,
|
||||
child: Instance | TextInstance,
|
||||
): void {
|
||||
RTManager.appendChildToContext(parentInstance, child);
|
||||
},
|
||||
|
||||
appendInitialChild(
|
||||
parentInstance: Instance,
|
||||
child: Instance | TextInstance,
|
||||
@@ -87,35 +76,6 @@ const NativeRTRenderer = ReactFiberReconciler({
|
||||
RTManager.appendChild(parentInstance, child);
|
||||
},
|
||||
|
||||
commitTextUpdate(
|
||||
textInstance: TextInstance,
|
||||
oldText: string,
|
||||
newText: string,
|
||||
): void {
|
||||
invariant(false, 'Text components are not yet supported.');
|
||||
},
|
||||
|
||||
commitMount(
|
||||
instance: Instance,
|
||||
type: string,
|
||||
newProps: Props,
|
||||
internalInstanceHandle: Object,
|
||||
): void {
|
||||
// Noop
|
||||
},
|
||||
|
||||
commitUpdate(
|
||||
instance: Instance,
|
||||
updatePayload: Object,
|
||||
type: string,
|
||||
oldProps: Props,
|
||||
newProps: Props,
|
||||
internalInstanceHandle: Object,
|
||||
): void {
|
||||
updateFiberProps(instance, newProps);
|
||||
RTManager.updateNode(instance, updatePayload);
|
||||
},
|
||||
|
||||
createInstance(
|
||||
type: string,
|
||||
props: Props,
|
||||
@@ -160,22 +120,6 @@ const NativeRTRenderer = ReactFiberReconciler({
|
||||
return instance;
|
||||
},
|
||||
|
||||
insertBefore(
|
||||
parentInstance: Instance,
|
||||
child: Instance | TextInstance,
|
||||
beforeChild: Instance | TextInstance,
|
||||
): void {
|
||||
RTManager.prependChild(child, beforeChild);
|
||||
},
|
||||
|
||||
insertInContainerBefore(
|
||||
parentInstance: Container,
|
||||
child: Instance | TextInstance,
|
||||
beforeChild: Instance | TextInstance,
|
||||
): void {
|
||||
RTManager.prependChild(child, beforeChild);
|
||||
},
|
||||
|
||||
prepareForCommit(): void {
|
||||
RTManager.beginUpdates();
|
||||
},
|
||||
@@ -194,27 +138,10 @@ const NativeRTRenderer = ReactFiberReconciler({
|
||||
return processProps(instance, newProps);
|
||||
},
|
||||
|
||||
removeChild(parentInstance: Instance, child: Instance | TextInstance): void {
|
||||
// TODO: recursively uncache, by traversing fibers, this will currently leak
|
||||
RTManager.deleteChild(child);
|
||||
},
|
||||
|
||||
removeChildFromContainer(
|
||||
parentInstance: Container,
|
||||
child: Instance | TextInstance,
|
||||
): void {
|
||||
// TODO: recursively uncache, by traversing fibers, this will currently leak
|
||||
RTManager.deleteChild(child);
|
||||
},
|
||||
|
||||
resetAfterCommit(): void {
|
||||
RTManager.completeUpdates();
|
||||
},
|
||||
|
||||
resetTextContent(instance: Instance): void {
|
||||
// Noop
|
||||
},
|
||||
|
||||
shouldDeprioritizeSubtree(type: string, props: Props): boolean {
|
||||
return false;
|
||||
},
|
||||
@@ -232,6 +159,87 @@ const NativeRTRenderer = ReactFiberReconciler({
|
||||
// TODO: Enable expiration by implementing this method.
|
||||
return 0;
|
||||
},
|
||||
|
||||
mutation: {
|
||||
appendChild(
|
||||
parentInstance: Instance,
|
||||
child: Instance | TextInstance,
|
||||
): void {
|
||||
RTManager.appendChild(parentInstance, child);
|
||||
},
|
||||
|
||||
appendChildToContainer(
|
||||
parentInstance: Container,
|
||||
child: Instance | TextInstance,
|
||||
): void {
|
||||
RTManager.appendChildToContext(parentInstance, child);
|
||||
},
|
||||
|
||||
commitTextUpdate(
|
||||
textInstance: TextInstance,
|
||||
oldText: string,
|
||||
newText: string,
|
||||
): void {
|
||||
invariant(false, 'Text components are not yet supported.');
|
||||
},
|
||||
|
||||
commitMount(
|
||||
instance: Instance,
|
||||
type: string,
|
||||
newProps: Props,
|
||||
internalInstanceHandle: Object,
|
||||
): void {
|
||||
// Noop
|
||||
},
|
||||
|
||||
commitUpdate(
|
||||
instance: Instance,
|
||||
updatePayload: Object,
|
||||
type: string,
|
||||
oldProps: Props,
|
||||
newProps: Props,
|
||||
internalInstanceHandle: Object,
|
||||
): void {
|
||||
updateFiberProps(instance, newProps);
|
||||
RTManager.updateNode(instance, updatePayload);
|
||||
},
|
||||
|
||||
insertBefore(
|
||||
parentInstance: Instance,
|
||||
child: Instance | TextInstance,
|
||||
beforeChild: Instance | TextInstance,
|
||||
): void {
|
||||
RTManager.prependChild(child, beforeChild);
|
||||
},
|
||||
|
||||
insertInContainerBefore(
|
||||
parentInstance: Container,
|
||||
child: Instance | TextInstance,
|
||||
beforeChild: Instance | TextInstance,
|
||||
): void {
|
||||
RTManager.prependChild(child, beforeChild);
|
||||
},
|
||||
|
||||
removeChild(
|
||||
parentInstance: Instance,
|
||||
child: Instance | TextInstance,
|
||||
): void {
|
||||
// TODO: recursively uncache, by traversing fibers, this will currently leak
|
||||
RTManager.deleteChild(child);
|
||||
},
|
||||
|
||||
removeChildFromContainer(
|
||||
parentInstance: Container,
|
||||
child: Instance | TextInstance,
|
||||
): void {
|
||||
// TODO: recursively uncache, by traversing fibers, this will currently leak
|
||||
RTManager.deleteChild(child);
|
||||
},
|
||||
|
||||
resetTextContent(instance: Instance): void {
|
||||
// Noop
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = NativeRTRenderer;
|
||||
|
||||
@@ -51,48 +51,6 @@ function recursivelyUncacheFiberNode(node: Instance | TextInstance) {
|
||||
}
|
||||
|
||||
const NativeRenderer = ReactFiberReconciler({
|
||||
appendChild(parentInstance: Instance, child: Instance | TextInstance): void {
|
||||
const childTag = typeof child === 'number' ? child : child._nativeTag;
|
||||
const children = parentInstance._children;
|
||||
const index = children.indexOf(child);
|
||||
|
||||
if (index >= 0) {
|
||||
children.splice(index, 1);
|
||||
children.push(child);
|
||||
|
||||
UIManager.manageChildren(
|
||||
parentInstance._nativeTag, // containerTag
|
||||
[index], // moveFromIndices
|
||||
[children.length - 1], // moveToIndices
|
||||
[], // addChildReactTags
|
||||
[], // addAtIndices
|
||||
[], // removeAtIndices
|
||||
);
|
||||
} else {
|
||||
children.push(child);
|
||||
|
||||
UIManager.manageChildren(
|
||||
parentInstance._nativeTag, // containerTag
|
||||
[], // moveFromIndices
|
||||
[], // moveToIndices
|
||||
[childTag], // addChildReactTags
|
||||
[children.length - 1], // addAtIndices
|
||||
[], // removeAtIndices
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
appendChildToContainer(
|
||||
parentInstance: Container,
|
||||
child: Instance | TextInstance,
|
||||
): void {
|
||||
const childTag = typeof child === 'number' ? child : child._nativeTag;
|
||||
UIManager.setChildren(
|
||||
parentInstance, // containerTag
|
||||
[childTag], // reactTags
|
||||
);
|
||||
},
|
||||
|
||||
appendInitialChild(
|
||||
parentInstance: Instance,
|
||||
child: Instance | TextInstance,
|
||||
@@ -100,57 +58,6 @@ const NativeRenderer = ReactFiberReconciler({
|
||||
parentInstance._children.push(child);
|
||||
},
|
||||
|
||||
commitTextUpdate(
|
||||
textInstance: TextInstance,
|
||||
oldText: string,
|
||||
newText: string,
|
||||
): void {
|
||||
UIManager.updateView(
|
||||
textInstance, // reactTag
|
||||
'RCTRawText', // viewName
|
||||
{text: newText}, // props
|
||||
);
|
||||
},
|
||||
|
||||
commitMount(
|
||||
instance: Instance,
|
||||
type: string,
|
||||
newProps: Props,
|
||||
internalInstanceHandle: Object,
|
||||
): void {
|
||||
// Noop
|
||||
},
|
||||
|
||||
commitUpdate(
|
||||
instance: Instance,
|
||||
updatePayloadTODO: Object,
|
||||
type: string,
|
||||
oldProps: Props,
|
||||
newProps: Props,
|
||||
internalInstanceHandle: Object,
|
||||
): void {
|
||||
const viewConfig = instance.viewConfig;
|
||||
|
||||
updateFiberProps(instance._nativeTag, newProps);
|
||||
|
||||
const updatePayload = ReactNativeAttributePayload.diff(
|
||||
oldProps,
|
||||
newProps,
|
||||
viewConfig.validAttributes,
|
||||
);
|
||||
|
||||
// Avoid the overhead of bridge calls if there's no update.
|
||||
// This is an expensive no-op for Android, and causes an unnecessary
|
||||
// view invalidation for certain components (eg RCTTextInput) on iOS.
|
||||
if (updatePayload != null) {
|
||||
UIManager.updateView(
|
||||
instance._nativeTag, // reactTag
|
||||
viewConfig.uiViewClassName, // viewName
|
||||
updatePayload, // props
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
createInstance(
|
||||
type: string,
|
||||
props: Props,
|
||||
@@ -251,60 +158,6 @@ const NativeRenderer = ReactFiberReconciler({
|
||||
return instance;
|
||||
},
|
||||
|
||||
insertBefore(
|
||||
parentInstance: Instance,
|
||||
child: Instance | TextInstance,
|
||||
beforeChild: Instance | TextInstance,
|
||||
): void {
|
||||
const children = (parentInstance: any)._children;
|
||||
const index = children.indexOf(child);
|
||||
|
||||
// Move existing child or add new child?
|
||||
if (index >= 0) {
|
||||
children.splice(index, 1);
|
||||
const beforeChildIndex = children.indexOf(beforeChild);
|
||||
children.splice(beforeChildIndex, 0, child);
|
||||
|
||||
UIManager.manageChildren(
|
||||
(parentInstance: any)._nativeTag, // containerID
|
||||
[index], // moveFromIndices
|
||||
[beforeChildIndex], // moveToIndices
|
||||
[], // addChildReactTags
|
||||
[], // addAtIndices
|
||||
[], // removeAtIndices
|
||||
);
|
||||
} else {
|
||||
const beforeChildIndex = children.indexOf(beforeChild);
|
||||
children.splice(beforeChildIndex, 0, child);
|
||||
|
||||
const childTag = typeof child === 'number' ? child : child._nativeTag;
|
||||
|
||||
UIManager.manageChildren(
|
||||
(parentInstance: any)._nativeTag, // containerID
|
||||
[], // moveFromIndices
|
||||
[], // moveToIndices
|
||||
[childTag], // addChildReactTags
|
||||
[beforeChildIndex], // addAtIndices
|
||||
[], // removeAtIndices
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
insertInContainerBefore(
|
||||
parentInstance: Container,
|
||||
child: Instance | TextInstance,
|
||||
beforeChild: Instance | TextInstance,
|
||||
): void {
|
||||
// TODO (bvaughn): Remove this check when...
|
||||
// We create a wrapper object for the container in ReactNative render()
|
||||
// Or we refactor to remove wrapper objects entirely.
|
||||
// For more info on pros/cons see PR #8560 description.
|
||||
invariant(
|
||||
typeof parentInstance !== 'number',
|
||||
'Container does not support insertBefore operation',
|
||||
);
|
||||
},
|
||||
|
||||
prepareForCommit(): void {
|
||||
// Noop
|
||||
},
|
||||
@@ -320,46 +173,10 @@ const NativeRenderer = ReactFiberReconciler({
|
||||
return emptyObject;
|
||||
},
|
||||
|
||||
removeChild(parentInstance: Instance, child: Instance | TextInstance): void {
|
||||
recursivelyUncacheFiberNode(child);
|
||||
const children = parentInstance._children;
|
||||
const index = children.indexOf(child);
|
||||
|
||||
children.splice(index, 1);
|
||||
|
||||
UIManager.manageChildren(
|
||||
parentInstance._nativeTag, // containerID
|
||||
[], // moveFromIndices
|
||||
[], // moveToIndices
|
||||
[], // addChildReactTags
|
||||
[], // addAtIndices
|
||||
[index], // removeAtIndices
|
||||
);
|
||||
},
|
||||
|
||||
removeChildFromContainer(
|
||||
parentInstance: Container,
|
||||
child: Instance | TextInstance,
|
||||
): void {
|
||||
recursivelyUncacheFiberNode(child);
|
||||
UIManager.manageChildren(
|
||||
parentInstance, // containerID
|
||||
[], // moveFromIndices
|
||||
[], // moveToIndices
|
||||
[], // addChildReactTags
|
||||
[], // addAtIndices
|
||||
[0], // removeAtIndices
|
||||
);
|
||||
},
|
||||
|
||||
resetAfterCommit(): void {
|
||||
// Noop
|
||||
},
|
||||
|
||||
resetTextContent(instance: Instance): void {
|
||||
// Noop
|
||||
},
|
||||
|
||||
shouldDeprioritizeSubtree(type: string, props: Props): boolean {
|
||||
return false;
|
||||
},
|
||||
@@ -382,6 +199,197 @@ const NativeRenderer = ReactFiberReconciler({
|
||||
// TODO: Enable expiration by implementing this method.
|
||||
return 0;
|
||||
},
|
||||
|
||||
mutation: {
|
||||
appendChild(
|
||||
parentInstance: Instance,
|
||||
child: Instance | TextInstance,
|
||||
): void {
|
||||
const childTag = typeof child === 'number' ? child : child._nativeTag;
|
||||
const children = parentInstance._children;
|
||||
const index = children.indexOf(child);
|
||||
|
||||
if (index >= 0) {
|
||||
children.splice(index, 1);
|
||||
children.push(child);
|
||||
|
||||
UIManager.manageChildren(
|
||||
parentInstance._nativeTag, // containerTag
|
||||
[index], // moveFromIndices
|
||||
[children.length - 1], // moveToIndices
|
||||
[], // addChildReactTags
|
||||
[], // addAtIndices
|
||||
[], // removeAtIndices
|
||||
);
|
||||
} else {
|
||||
children.push(child);
|
||||
|
||||
UIManager.manageChildren(
|
||||
parentInstance._nativeTag, // containerTag
|
||||
[], // moveFromIndices
|
||||
[], // moveToIndices
|
||||
[childTag], // addChildReactTags
|
||||
[children.length - 1], // addAtIndices
|
||||
[], // removeAtIndices
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
appendChildToContainer(
|
||||
parentInstance: Container,
|
||||
child: Instance | TextInstance,
|
||||
): void {
|
||||
const childTag = typeof child === 'number' ? child : child._nativeTag;
|
||||
UIManager.setChildren(
|
||||
parentInstance, // containerTag
|
||||
[childTag], // reactTags
|
||||
);
|
||||
},
|
||||
|
||||
commitTextUpdate(
|
||||
textInstance: TextInstance,
|
||||
oldText: string,
|
||||
newText: string,
|
||||
): void {
|
||||
UIManager.updateView(
|
||||
textInstance, // reactTag
|
||||
'RCTRawText', // viewName
|
||||
{text: newText}, // props
|
||||
);
|
||||
},
|
||||
|
||||
commitMount(
|
||||
instance: Instance,
|
||||
type: string,
|
||||
newProps: Props,
|
||||
internalInstanceHandle: Object,
|
||||
): void {
|
||||
// Noop
|
||||
},
|
||||
|
||||
commitUpdate(
|
||||
instance: Instance,
|
||||
updatePayloadTODO: Object,
|
||||
type: string,
|
||||
oldProps: Props,
|
||||
newProps: Props,
|
||||
internalInstanceHandle: Object,
|
||||
): void {
|
||||
const viewConfig = instance.viewConfig;
|
||||
|
||||
updateFiberProps(instance._nativeTag, newProps);
|
||||
|
||||
const updatePayload = ReactNativeAttributePayload.diff(
|
||||
oldProps,
|
||||
newProps,
|
||||
viewConfig.validAttributes,
|
||||
);
|
||||
|
||||
// Avoid the overhead of bridge calls if there's no update.
|
||||
// This is an expensive no-op for Android, and causes an unnecessary
|
||||
// view invalidation for certain components (eg RCTTextInput) on iOS.
|
||||
if (updatePayload != null) {
|
||||
UIManager.updateView(
|
||||
instance._nativeTag, // reactTag
|
||||
viewConfig.uiViewClassName, // viewName
|
||||
updatePayload, // props
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
insertBefore(
|
||||
parentInstance: Instance,
|
||||
child: Instance | TextInstance,
|
||||
beforeChild: Instance | TextInstance,
|
||||
): void {
|
||||
const children = (parentInstance: any)._children;
|
||||
const index = children.indexOf(child);
|
||||
|
||||
// Move existing child or add new child?
|
||||
if (index >= 0) {
|
||||
children.splice(index, 1);
|
||||
const beforeChildIndex = children.indexOf(beforeChild);
|
||||
children.splice(beforeChildIndex, 0, child);
|
||||
|
||||
UIManager.manageChildren(
|
||||
(parentInstance: any)._nativeTag, // containerID
|
||||
[index], // moveFromIndices
|
||||
[beforeChildIndex], // moveToIndices
|
||||
[], // addChildReactTags
|
||||
[], // addAtIndices
|
||||
[], // removeAtIndices
|
||||
);
|
||||
} else {
|
||||
const beforeChildIndex = children.indexOf(beforeChild);
|
||||
children.splice(beforeChildIndex, 0, child);
|
||||
|
||||
const childTag = typeof child === 'number' ? child : child._nativeTag;
|
||||
|
||||
UIManager.manageChildren(
|
||||
(parentInstance: any)._nativeTag, // containerID
|
||||
[], // moveFromIndices
|
||||
[], // moveToIndices
|
||||
[childTag], // addChildReactTags
|
||||
[beforeChildIndex], // addAtIndices
|
||||
[], // removeAtIndices
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
insertInContainerBefore(
|
||||
parentInstance: Container,
|
||||
child: Instance | TextInstance,
|
||||
beforeChild: Instance | TextInstance,
|
||||
): void {
|
||||
// TODO (bvaughn): Remove this check when...
|
||||
// We create a wrapper object for the container in ReactNative render()
|
||||
// Or we refactor to remove wrapper objects entirely.
|
||||
// For more info on pros/cons see PR #8560 description.
|
||||
invariant(
|
||||
typeof parentInstance !== 'number',
|
||||
'Container does not support insertBefore operation',
|
||||
);
|
||||
},
|
||||
|
||||
removeChild(
|
||||
parentInstance: Instance,
|
||||
child: Instance | TextInstance,
|
||||
): void {
|
||||
recursivelyUncacheFiberNode(child);
|
||||
const children = parentInstance._children;
|
||||
const index = children.indexOf(child);
|
||||
|
||||
children.splice(index, 1);
|
||||
|
||||
UIManager.manageChildren(
|
||||
parentInstance._nativeTag, // containerID
|
||||
[], // moveFromIndices
|
||||
[], // moveToIndices
|
||||
[], // addChildReactTags
|
||||
[], // addAtIndices
|
||||
[index], // removeAtIndices
|
||||
);
|
||||
},
|
||||
|
||||
removeChildFromContainer(
|
||||
parentInstance: Container,
|
||||
child: Instance | TextInstance,
|
||||
): void {
|
||||
recursivelyUncacheFiberNode(child);
|
||||
UIManager.manageChildren(
|
||||
parentInstance, // containerID
|
||||
[], // moveFromIndices
|
||||
[], // moveToIndices
|
||||
[], // addChildReactTags
|
||||
[], // addAtIndices
|
||||
[0], // removeAtIndices
|
||||
);
|
||||
},
|
||||
|
||||
resetTextContent(instance: Instance): void {
|
||||
// Noop
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = NativeRenderer;
|
||||
|
||||
@@ -137,28 +137,12 @@ var NoopRenderer = ReactFiberReconciler({
|
||||
return UPDATE_SIGNAL;
|
||||
},
|
||||
|
||||
commitMount(instance: Instance, type: string, newProps: Props): void {
|
||||
// Noop
|
||||
},
|
||||
|
||||
commitUpdate(
|
||||
instance: Instance,
|
||||
updatePayload: Object,
|
||||
type: string,
|
||||
oldProps: Props,
|
||||
newProps: Props,
|
||||
): void {
|
||||
instance.prop = newProps.prop;
|
||||
},
|
||||
|
||||
shouldSetTextContent(type: string, props: Props): boolean {
|
||||
return (
|
||||
typeof props.children === 'string' || typeof props.children === 'number'
|
||||
);
|
||||
},
|
||||
|
||||
resetTextContent(instance: Instance): void {},
|
||||
|
||||
shouldDeprioritizeSubtree(type: string, props: Props): boolean {
|
||||
return !!props.hidden;
|
||||
},
|
||||
@@ -175,21 +159,6 @@ var NoopRenderer = ReactFiberReconciler({
|
||||
return inst;
|
||||
},
|
||||
|
||||
commitTextUpdate(
|
||||
textInstance: TextInstance,
|
||||
oldText: string,
|
||||
newText: string,
|
||||
): void {
|
||||
textInstance.text = newText;
|
||||
},
|
||||
|
||||
appendChild: appendChild,
|
||||
appendChildToContainer: appendChild,
|
||||
insertBefore: insertBefore,
|
||||
insertInContainerBefore: insertBefore,
|
||||
removeChild: removeChild,
|
||||
removeChildFromContainer: removeChild,
|
||||
|
||||
scheduleDeferredCallback(callback) {
|
||||
if (scheduledCallback) {
|
||||
throw new Error(
|
||||
@@ -207,6 +176,39 @@ var NoopRenderer = ReactFiberReconciler({
|
||||
now(): number {
|
||||
return elapsedTimeInMs;
|
||||
},
|
||||
|
||||
mutation: {
|
||||
commitMount(instance: Instance, type: string, newProps: Props): void {
|
||||
// Noop
|
||||
},
|
||||
|
||||
commitUpdate(
|
||||
instance: Instance,
|
||||
updatePayload: Object,
|
||||
type: string,
|
||||
oldProps: Props,
|
||||
newProps: Props,
|
||||
): void {
|
||||
instance.prop = newProps.prop;
|
||||
},
|
||||
|
||||
commitTextUpdate(
|
||||
textInstance: TextInstance,
|
||||
oldText: string,
|
||||
newText: string,
|
||||
): void {
|
||||
textInstance.text = newText;
|
||||
},
|
||||
|
||||
appendChild: appendChild,
|
||||
appendChildToContainer: appendChild,
|
||||
insertBefore: insertBefore,
|
||||
insertInContainerBefore: insertBefore,
|
||||
removeChild: removeChild,
|
||||
removeChildFromContainer: removeChild,
|
||||
|
||||
resetTextContent(instance: Instance): void {},
|
||||
},
|
||||
});
|
||||
|
||||
var rootContainers = new Map();
|
||||
|
||||
@@ -47,19 +47,7 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
|
||||
config: HostConfig<T, P, I, TI, PI, C, CX, PL>,
|
||||
captureError: (failedFiber: Fiber, error: mixed) => Fiber | null,
|
||||
) {
|
||||
const {
|
||||
commitMount,
|
||||
commitUpdate,
|
||||
resetTextContent,
|
||||
commitTextUpdate,
|
||||
appendChild,
|
||||
appendChildToContainer,
|
||||
insertBefore,
|
||||
insertInContainerBefore,
|
||||
removeChild,
|
||||
removeChildFromContainer,
|
||||
getPublicInstance,
|
||||
} = config;
|
||||
const {getPublicInstance} = config;
|
||||
|
||||
if (__DEV__) {
|
||||
var callComponentWillUnmountWithTimerInDev = function(current, instance) {
|
||||
@@ -115,6 +103,213 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
|
||||
}
|
||||
}
|
||||
|
||||
function commitLifeCycles(current: Fiber | null, finishedWork: Fiber): void {
|
||||
switch (finishedWork.tag) {
|
||||
case ClassComponent: {
|
||||
const instance = finishedWork.stateNode;
|
||||
if (finishedWork.effectTag & Update) {
|
||||
if (current === null) {
|
||||
if (__DEV__) {
|
||||
startPhaseTimer(finishedWork, 'componentDidMount');
|
||||
}
|
||||
instance.props = finishedWork.memoizedProps;
|
||||
instance.state = finishedWork.memoizedState;
|
||||
instance.componentDidMount();
|
||||
if (__DEV__) {
|
||||
stopPhaseTimer();
|
||||
}
|
||||
} else {
|
||||
const prevProps = current.memoizedProps;
|
||||
const prevState = current.memoizedState;
|
||||
if (__DEV__) {
|
||||
startPhaseTimer(finishedWork, 'componentDidUpdate');
|
||||
}
|
||||
instance.props = finishedWork.memoizedProps;
|
||||
instance.state = finishedWork.memoizedState;
|
||||
instance.componentDidUpdate(prevProps, prevState);
|
||||
if (__DEV__) {
|
||||
stopPhaseTimer();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (
|
||||
finishedWork.effectTag & Callback &&
|
||||
finishedWork.updateQueue !== null
|
||||
) {
|
||||
commitCallbacks(finishedWork, finishedWork.updateQueue, instance);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case HostRoot: {
|
||||
const updateQueue = finishedWork.updateQueue;
|
||||
if (updateQueue !== null) {
|
||||
const instance = finishedWork.child && finishedWork.child.stateNode;
|
||||
commitCallbacks(finishedWork, updateQueue, instance);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case HostComponent: {
|
||||
const instance: I = finishedWork.stateNode;
|
||||
|
||||
// Renderers may schedule work to be done after host components are mounted
|
||||
// (eg DOM renderer may schedule auto-focus for inputs and form controls).
|
||||
// These effects should only be committed when components are first mounted,
|
||||
// aka when there is no current/alternate.
|
||||
if (current === null && finishedWork.effectTag & Update) {
|
||||
const type = finishedWork.type;
|
||||
const props = finishedWork.memoizedProps;
|
||||
commitMount(instance, type, props, finishedWork);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
case HostText: {
|
||||
// We have no life-cycles associated with text.
|
||||
return;
|
||||
}
|
||||
case HostPortal: {
|
||||
// We have no life-cycles associated with portals.
|
||||
return;
|
||||
}
|
||||
default: {
|
||||
invariant(
|
||||
false,
|
||||
'This unit of work tag should not have side-effects. This error is ' +
|
||||
'likely caused by a bug in React. Please file an issue.',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function commitAttachRef(finishedWork: Fiber) {
|
||||
const ref = finishedWork.ref;
|
||||
if (ref !== null) {
|
||||
const instance = finishedWork.stateNode;
|
||||
switch (finishedWork.tag) {
|
||||
case HostComponent:
|
||||
ref(getPublicInstance(instance));
|
||||
break;
|
||||
default:
|
||||
ref(instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function commitDetachRef(current: Fiber) {
|
||||
const currentRef = current.ref;
|
||||
if (currentRef !== null) {
|
||||
currentRef(null);
|
||||
}
|
||||
}
|
||||
|
||||
// User-originating errors (lifecycles and refs) should not interrupt
|
||||
// deletion, so don't let them throw. Host-originating errors should
|
||||
// interrupt deletion, so it's okay
|
||||
function commitUnmount(current: Fiber): void {
|
||||
if (typeof onCommitUnmount === 'function') {
|
||||
onCommitUnmount(current);
|
||||
}
|
||||
|
||||
switch (current.tag) {
|
||||
case ClassComponent: {
|
||||
safelyDetachRef(current);
|
||||
const instance = current.stateNode;
|
||||
if (typeof instance.componentWillUnmount === 'function') {
|
||||
safelyCallComponentWillUnmount(current, instance);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case HostComponent: {
|
||||
safelyDetachRef(current);
|
||||
return;
|
||||
}
|
||||
case CoroutineComponent: {
|
||||
commitNestedUnmounts(current.stateNode);
|
||||
return;
|
||||
}
|
||||
case HostPortal: {
|
||||
// TODO: this is recursive.
|
||||
// We are also not using this parent because
|
||||
// the portal will get pushed immediately.
|
||||
unmountHostComponents(current);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function commitNestedUnmounts(root: Fiber): void {
|
||||
// While we're inside a removed host node we don't want to call
|
||||
// removeChild on the inner nodes because they're removed by the top
|
||||
// call anyway. We also want to call componentWillUnmount on all
|
||||
// composites before this host node is removed from the tree. Therefore
|
||||
// we do an inner loop while we're still inside the host node.
|
||||
let node: Fiber = root;
|
||||
while (true) {
|
||||
commitUnmount(node);
|
||||
// Visit children because they may contain more composite or host nodes.
|
||||
// Skip portals because commitUnmount() currently visits them recursively.
|
||||
if (node.child !== null && node.tag !== HostPortal) {
|
||||
node.child.return = node;
|
||||
node = node.child;
|
||||
continue;
|
||||
}
|
||||
if (node === root) {
|
||||
return;
|
||||
}
|
||||
while (node.sibling === null) {
|
||||
if (node.return === null || node.return === root) {
|
||||
return;
|
||||
}
|
||||
node = node.return;
|
||||
}
|
||||
node.sibling.return = node.return;
|
||||
node = node.sibling;
|
||||
}
|
||||
}
|
||||
|
||||
function detachFiber(current: Fiber) {
|
||||
// Cut off the return pointers to disconnect it from the tree. Ideally, we
|
||||
// should clear the child pointer of the parent alternate to let this
|
||||
// get GC:ed but we don't know which for sure which parent is the current
|
||||
// one so we'll settle for GC:ing the subtree of this child. This child
|
||||
// itself will be GC:ed when the parent updates the next time.
|
||||
current.return = null;
|
||||
current.child = null;
|
||||
if (current.alternate) {
|
||||
current.alternate.child = null;
|
||||
current.alternate.return = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!config.mutation) {
|
||||
return {
|
||||
commitResetTextContent(finishedWork: Fiber) {},
|
||||
commitPlacement(finishedWork: Fiber) {},
|
||||
commitDeletion(current: Fiber) {
|
||||
// Detach refs and call componentWillUnmount() on the whole subtree.
|
||||
commitNestedUnmounts(current);
|
||||
detachFiber(current);
|
||||
},
|
||||
commitWork(current: Fiber | null, finishedWork: Fiber) {},
|
||||
commitLifeCycles,
|
||||
commitAttachRef,
|
||||
commitDetachRef,
|
||||
};
|
||||
}
|
||||
|
||||
const {
|
||||
commitMount,
|
||||
commitUpdate,
|
||||
resetTextContent,
|
||||
commitTextUpdate,
|
||||
appendChild,
|
||||
appendChildToContainer,
|
||||
insertBefore,
|
||||
insertInContainerBefore,
|
||||
removeChild,
|
||||
removeChildFromContainer,
|
||||
} = config.mutation;
|
||||
|
||||
function getHostParentFiber(fiber: Fiber): Fiber {
|
||||
let parent = fiber.return;
|
||||
while (parent !== null) {
|
||||
@@ -254,36 +449,6 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
|
||||
}
|
||||
}
|
||||
|
||||
function commitNestedUnmounts(root: Fiber): void {
|
||||
// While we're inside a removed host node we don't want to call
|
||||
// removeChild on the inner nodes because they're removed by the top
|
||||
// call anyway. We also want to call componentWillUnmount on all
|
||||
// composites before this host node is removed from the tree. Therefore
|
||||
// we do an inner loop while we're still inside the host node.
|
||||
let node: Fiber = root;
|
||||
while (true) {
|
||||
commitUnmount(node);
|
||||
// Visit children because they may contain more composite or host nodes.
|
||||
// Skip portals because commitUnmount() currently visits them recursively.
|
||||
if (node.child !== null && node.tag !== HostPortal) {
|
||||
node.child.return = node;
|
||||
node = node.child;
|
||||
continue;
|
||||
}
|
||||
if (node === root) {
|
||||
return;
|
||||
}
|
||||
while (node.sibling === null) {
|
||||
if (node.return === null || node.return === root) {
|
||||
return;
|
||||
}
|
||||
node = node.return;
|
||||
}
|
||||
node.sibling.return = node.return;
|
||||
node = node.sibling;
|
||||
}
|
||||
}
|
||||
|
||||
function unmountHostComponents(current): void {
|
||||
// We only have the top Fiber that was inserted but we need recurse down its
|
||||
// children to find all the terminal nodes.
|
||||
@@ -375,53 +540,7 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
|
||||
// Recursively delete all host nodes from the parent.
|
||||
// Detach refs and call componentWillUnmount() on the whole subtree.
|
||||
unmountHostComponents(current);
|
||||
|
||||
// Cut off the return pointers to disconnect it from the tree. Ideally, we
|
||||
// should clear the child pointer of the parent alternate to let this
|
||||
// get GC:ed but we don't know which for sure which parent is the current
|
||||
// one so we'll settle for GC:ing the subtree of this child. This child
|
||||
// itself will be GC:ed when the parent updates the next time.
|
||||
current.return = null;
|
||||
current.child = null;
|
||||
if (current.alternate) {
|
||||
current.alternate.child = null;
|
||||
current.alternate.return = null;
|
||||
}
|
||||
}
|
||||
|
||||
// User-originating errors (lifecycles and refs) should not interrupt
|
||||
// deletion, so don't let them throw. Host-originating errors should
|
||||
// interrupt deletion, so it's okay
|
||||
function commitUnmount(current: Fiber): void {
|
||||
if (typeof onCommitUnmount === 'function') {
|
||||
onCommitUnmount(current);
|
||||
}
|
||||
|
||||
switch (current.tag) {
|
||||
case ClassComponent: {
|
||||
safelyDetachRef(current);
|
||||
const instance = current.stateNode;
|
||||
if (typeof instance.componentWillUnmount === 'function') {
|
||||
safelyCallComponentWillUnmount(current, instance);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case HostComponent: {
|
||||
safelyDetachRef(current);
|
||||
return;
|
||||
}
|
||||
case CoroutineComponent: {
|
||||
commitNestedUnmounts(current.stateNode);
|
||||
return;
|
||||
}
|
||||
case HostPortal: {
|
||||
// TODO: this is recursive.
|
||||
// We are also not using this parent because
|
||||
// the portal will get pushed immediately.
|
||||
unmountHostComponents(current);
|
||||
return;
|
||||
}
|
||||
}
|
||||
detachFiber(current);
|
||||
}
|
||||
|
||||
function commitWork(current: Fiber | null, finishedWork: Fiber): void {
|
||||
@@ -488,106 +607,12 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
|
||||
}
|
||||
}
|
||||
|
||||
function commitLifeCycles(current: Fiber | null, finishedWork: Fiber): void {
|
||||
switch (finishedWork.tag) {
|
||||
case ClassComponent: {
|
||||
const instance = finishedWork.stateNode;
|
||||
if (finishedWork.effectTag & Update) {
|
||||
if (current === null) {
|
||||
if (__DEV__) {
|
||||
startPhaseTimer(finishedWork, 'componentDidMount');
|
||||
}
|
||||
instance.props = finishedWork.memoizedProps;
|
||||
instance.state = finishedWork.memoizedState;
|
||||
instance.componentDidMount();
|
||||
if (__DEV__) {
|
||||
stopPhaseTimer();
|
||||
}
|
||||
} else {
|
||||
const prevProps = current.memoizedProps;
|
||||
const prevState = current.memoizedState;
|
||||
if (__DEV__) {
|
||||
startPhaseTimer(finishedWork, 'componentDidUpdate');
|
||||
}
|
||||
instance.props = finishedWork.memoizedProps;
|
||||
instance.state = finishedWork.memoizedState;
|
||||
instance.componentDidUpdate(prevProps, prevState);
|
||||
if (__DEV__) {
|
||||
stopPhaseTimer();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (
|
||||
finishedWork.effectTag & Callback &&
|
||||
finishedWork.updateQueue !== null
|
||||
) {
|
||||
commitCallbacks(finishedWork, finishedWork.updateQueue, instance);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case HostRoot: {
|
||||
const updateQueue = finishedWork.updateQueue;
|
||||
if (updateQueue !== null) {
|
||||
const instance = finishedWork.child && finishedWork.child.stateNode;
|
||||
commitCallbacks(finishedWork, updateQueue, instance);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case HostComponent: {
|
||||
const instance: I = finishedWork.stateNode;
|
||||
|
||||
// Renderers may schedule work to be done after host components are mounted
|
||||
// (eg DOM renderer may schedule auto-focus for inputs and form controls).
|
||||
// These effects should only be committed when components are first mounted,
|
||||
// aka when there is no current/alternate.
|
||||
if (current === null && finishedWork.effectTag & Update) {
|
||||
const type = finishedWork.type;
|
||||
const props = finishedWork.memoizedProps;
|
||||
commitMount(instance, type, props, finishedWork);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
case HostText: {
|
||||
// We have no life-cycles associated with text.
|
||||
return;
|
||||
}
|
||||
case HostPortal: {
|
||||
// We have no life-cycles associated with portals.
|
||||
return;
|
||||
}
|
||||
default: {
|
||||
invariant(
|
||||
false,
|
||||
'This unit of work tag should not have side-effects. This error is ' +
|
||||
'likely caused by a bug in React. Please file an issue.',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function commitAttachRef(finishedWork: Fiber) {
|
||||
const ref = finishedWork.ref;
|
||||
if (ref !== null) {
|
||||
const instance = finishedWork.stateNode;
|
||||
switch (finishedWork.tag) {
|
||||
case HostComponent:
|
||||
ref(getPublicInstance(instance));
|
||||
break;
|
||||
default:
|
||||
ref(instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function commitDetachRef(current: Fiber) {
|
||||
const currentRef = current.ref;
|
||||
if (currentRef !== null) {
|
||||
currentRef(null);
|
||||
}
|
||||
function commitResetTextContent(current: Fiber) {
|
||||
resetTextContent(current.stateNode);
|
||||
}
|
||||
|
||||
return {
|
||||
commitResetTextContent,
|
||||
commitPlacement,
|
||||
commitDeletion,
|
||||
commitWork,
|
||||
|
||||
@@ -36,42 +36,10 @@ export type HydrationContext<C, CX> = {
|
||||
module.exports = function<T, P, I, TI, PI, C, CX, PL>(
|
||||
config: HostConfig<T, P, I, TI, PI, C, CX, PL>,
|
||||
): HydrationContext<C, CX> {
|
||||
const {
|
||||
shouldSetTextContent,
|
||||
canHydrateInstance,
|
||||
canHydrateTextInstance,
|
||||
getNextHydratableSibling,
|
||||
getFirstHydratableChild,
|
||||
hydrateInstance,
|
||||
hydrateTextInstance,
|
||||
didNotMatchHydratedContainerTextInstance,
|
||||
didNotMatchHydratedTextInstance,
|
||||
didNotHydrateContainerInstance,
|
||||
didNotHydrateInstance,
|
||||
// TODO: These are currently unused, see below.
|
||||
// didNotFindHydratableContainerInstance,
|
||||
// didNotFindHydratableContainerTextInstance,
|
||||
didNotFindHydratableInstance,
|
||||
didNotFindHydratableTextInstance,
|
||||
} = config;
|
||||
const {shouldSetTextContent, hydration} = config;
|
||||
|
||||
// If this doesn't have hydration mode.
|
||||
if (
|
||||
!(canHydrateInstance &&
|
||||
canHydrateTextInstance &&
|
||||
getNextHydratableSibling &&
|
||||
getFirstHydratableChild &&
|
||||
hydrateInstance &&
|
||||
hydrateTextInstance &&
|
||||
didNotMatchHydratedContainerTextInstance &&
|
||||
didNotMatchHydratedTextInstance &&
|
||||
didNotHydrateContainerInstance &&
|
||||
didNotHydrateInstance &&
|
||||
// didNotFindHydratableContainerInstance &&
|
||||
// didNotFindHydratableContainerTextInstance &&
|
||||
didNotFindHydratableInstance &&
|
||||
didNotFindHydratableTextInstance)
|
||||
) {
|
||||
if (!hydration) {
|
||||
return {
|
||||
enterHydrationState() {
|
||||
return false;
|
||||
@@ -98,6 +66,24 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
|
||||
};
|
||||
}
|
||||
|
||||
const {
|
||||
canHydrateInstance,
|
||||
canHydrateTextInstance,
|
||||
getNextHydratableSibling,
|
||||
getFirstHydratableChild,
|
||||
hydrateInstance,
|
||||
hydrateTextInstance,
|
||||
didNotMatchHydratedContainerTextInstance,
|
||||
didNotMatchHydratedTextInstance,
|
||||
didNotHydrateContainerInstance,
|
||||
didNotHydrateInstance,
|
||||
// TODO: These are currently unused, see below.
|
||||
// didNotFindHydratableContainerInstance,
|
||||
// didNotFindHydratableContainerTextInstance,
|
||||
didNotFindHydratableInstance,
|
||||
didNotFindHydratableTextInstance,
|
||||
} = hydration;
|
||||
|
||||
// The deepest Fiber on the stack involved in a hydration context.
|
||||
// This may have been an insertion or a hydration.
|
||||
let hydrationParentFiber: null | Fiber = null;
|
||||
|
||||
@@ -77,6 +77,35 @@ export type HostConfig<T, P, I, TI, PI, C, CX, PL> = {
|
||||
rootContainerInstance: C,
|
||||
hostContext: CX,
|
||||
): null | PL,
|
||||
|
||||
shouldSetTextContent(type: T, props: P): boolean,
|
||||
shouldDeprioritizeSubtree(type: T, props: P): boolean,
|
||||
|
||||
createTextInstance(
|
||||
text: string,
|
||||
rootContainerInstance: C,
|
||||
hostContext: CX,
|
||||
internalInstanceHandle: OpaqueHandle,
|
||||
): TI,
|
||||
|
||||
scheduleDeferredCallback(
|
||||
callback: (deadline: Deadline) => void,
|
||||
): number | void,
|
||||
|
||||
prepareForCommit(): void,
|
||||
resetAfterCommit(): void,
|
||||
|
||||
now(): number,
|
||||
|
||||
useSyncScheduling?: boolean,
|
||||
|
||||
+hydration?: HydrationHostConfig<T, P, I, TI, C, CX, PL>,
|
||||
|
||||
+mutation?: MutableUpdatesHostConfig<T, P, I, TI, C, PL>,
|
||||
+persistence?: PersistentUpdatesHostConfig<T, P, I, C, CX, PL>,
|
||||
};
|
||||
|
||||
type MutableUpdatesHostConfig<T, P, I, TI, C, PL> = {
|
||||
commitUpdate(
|
||||
instance: I,
|
||||
updatePayload: PL,
|
||||
@@ -91,19 +120,8 @@ export type HostConfig<T, P, I, TI, PI, C, CX, PL> = {
|
||||
newProps: P,
|
||||
internalInstanceHandle: OpaqueHandle,
|
||||
): void,
|
||||
|
||||
shouldSetTextContent(type: T, props: P): boolean,
|
||||
resetTextContent(instance: I): void,
|
||||
shouldDeprioritizeSubtree(type: T, props: P): boolean,
|
||||
|
||||
createTextInstance(
|
||||
text: string,
|
||||
rootContainerInstance: C,
|
||||
hostContext: CX,
|
||||
internalInstanceHandle: OpaqueHandle,
|
||||
): TI,
|
||||
commitTextUpdate(textInstance: TI, oldText: string, newText: string): void,
|
||||
|
||||
resetTextContent(instance: I): void,
|
||||
appendChild(parentInstance: I, child: I | TI): void,
|
||||
appendChildToContainer(container: C, child: I | TI): void,
|
||||
insertBefore(parentInstance: I, child: I | TI, beforeChild: I | TI): void,
|
||||
@@ -114,80 +132,92 @@ export type HostConfig<T, P, I, TI, PI, C, CX, PL> = {
|
||||
): void,
|
||||
removeChild(parentInstance: I, child: I | TI): void,
|
||||
removeChildFromContainer(container: C, child: I | TI): void,
|
||||
};
|
||||
|
||||
scheduleDeferredCallback(
|
||||
callback: (deadline: Deadline) => void,
|
||||
): number | void,
|
||||
type PersistentUpdatesHostConfig<T, P, I, C, CX, PL> = {
|
||||
cloneInstance(
|
||||
instance: I,
|
||||
updatePayload: PL,
|
||||
type: T,
|
||||
oldProps: P,
|
||||
newProps: P,
|
||||
internalInstanceHandle: OpaqueHandle,
|
||||
keepChildren: boolean,
|
||||
): I,
|
||||
tryToReuseInstance(
|
||||
instance: I,
|
||||
updatePayload: PL,
|
||||
type: T,
|
||||
oldProps: P,
|
||||
newProps: P,
|
||||
internalInstanceHandle: OpaqueHandle,
|
||||
keepChildren: boolean,
|
||||
): I,
|
||||
|
||||
prepareForCommit(): void,
|
||||
resetAfterCommit(): void,
|
||||
|
||||
now(): number,
|
||||
createRootInstance(rootContainerInstance: C, hostContext: CX): I,
|
||||
commitRootInstance(rootInstance: I): void,
|
||||
};
|
||||
|
||||
type HydrationHostConfig<T, P, I, TI, C, CX, PL> = {
|
||||
// Optional hydration
|
||||
canHydrateInstance?: (instance: I | TI, type: T, props: P) => boolean,
|
||||
canHydrateTextInstance?: (instance: I | TI, text: string) => boolean,
|
||||
getNextHydratableSibling?: (instance: I | TI) => null | I | TI,
|
||||
getFirstHydratableChild?: (parentInstance: I | C) => null | I | TI,
|
||||
hydrateInstance?: (
|
||||
canHydrateInstance(instance: I | TI, type: T, props: P): boolean,
|
||||
canHydrateTextInstance(instance: I | TI, text: string): boolean,
|
||||
getNextHydratableSibling(instance: I | TI): null | I | TI,
|
||||
getFirstHydratableChild(parentInstance: I | C): null | I | TI,
|
||||
hydrateInstance(
|
||||
instance: I,
|
||||
type: T,
|
||||
props: P,
|
||||
rootContainerInstance: C,
|
||||
hostContext: CX,
|
||||
internalInstanceHandle: OpaqueHandle,
|
||||
) => null | PL,
|
||||
hydrateTextInstance?: (
|
||||
): null | PL,
|
||||
hydrateTextInstance(
|
||||
textInstance: TI,
|
||||
text: string,
|
||||
internalInstanceHandle: OpaqueHandle,
|
||||
) => boolean,
|
||||
didNotMatchHydratedContainerTextInstance?: (
|
||||
): boolean,
|
||||
didNotMatchHydratedContainerTextInstance(
|
||||
parentContainer: C,
|
||||
textInstance: TI,
|
||||
text: string,
|
||||
) => void,
|
||||
didNotMatchHydratedTextInstance?: (
|
||||
): void,
|
||||
didNotMatchHydratedTextInstance(
|
||||
parentType: T,
|
||||
parentProps: P,
|
||||
parentInstance: I,
|
||||
textInstance: TI,
|
||||
text: string,
|
||||
) => void,
|
||||
didNotHydrateContainerInstance?: (
|
||||
parentContainer: C,
|
||||
instance: I | TI,
|
||||
) => void,
|
||||
didNotHydrateInstance?: (
|
||||
): void,
|
||||
didNotHydrateContainerInstance(parentContainer: C, instance: I | TI): void,
|
||||
didNotHydrateInstance(
|
||||
parentType: T,
|
||||
parentProps: P,
|
||||
parentInstance: I,
|
||||
instance: I | TI,
|
||||
) => void,
|
||||
didNotFindHydratableContainerInstance?: (
|
||||
): void,
|
||||
didNotFindHydratableContainerInstance(
|
||||
parentContainer: C,
|
||||
type: T,
|
||||
props: P,
|
||||
) => void,
|
||||
didNotFindHydratableContainerTextInstance?: (
|
||||
): void,
|
||||
didNotFindHydratableContainerTextInstance(
|
||||
parentContainer: C,
|
||||
text: string,
|
||||
) => void,
|
||||
didNotFindHydratableInstance?: (
|
||||
): void,
|
||||
didNotFindHydratableInstance(
|
||||
parentType: T,
|
||||
parentProps: P,
|
||||
parentInstance: I,
|
||||
type: T,
|
||||
props: P,
|
||||
) => void,
|
||||
didNotFindHydratableTextInstance?: (
|
||||
): void,
|
||||
didNotFindHydratableTextInstance(
|
||||
parentType: T,
|
||||
parentProps: P,
|
||||
parentInstance: I,
|
||||
text: string,
|
||||
) => void,
|
||||
|
||||
useSyncScheduling?: boolean,
|
||||
): void,
|
||||
};
|
||||
|
||||
export type Reconciler<C, I, TI> = {
|
||||
|
||||
@@ -174,6 +174,7 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
|
||||
hydrationContext,
|
||||
);
|
||||
const {
|
||||
commitResetTextContent,
|
||||
commitPlacement,
|
||||
commitDeletion,
|
||||
commitWork,
|
||||
@@ -332,7 +333,7 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
|
||||
|
||||
const effectTag = nextEffect.effectTag;
|
||||
if (effectTag & ContentReset) {
|
||||
config.resetTextContent(nextEffect.stateNode);
|
||||
commitResetTextContent(nextEffect);
|
||||
}
|
||||
|
||||
if (effectTag & Ref) {
|
||||
|
||||
@@ -43,13 +43,15 @@ describe('ReactFiberHostContext', () => {
|
||||
appendInitialChild: function() {
|
||||
return null;
|
||||
},
|
||||
appendChildToContainer: function() {
|
||||
return null;
|
||||
},
|
||||
now: function() {
|
||||
return 0;
|
||||
},
|
||||
useSyncScheduling: true,
|
||||
mutation: {
|
||||
appendChildToContainer: function() {
|
||||
return null;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const container = Renderer.createContainer(/* root: */ null);
|
||||
|
||||
@@ -180,35 +180,10 @@ var TestRenderer = ReactFiberReconciler({
|
||||
return UPDATE_SIGNAL;
|
||||
},
|
||||
|
||||
commitUpdate(
|
||||
instance: Instance,
|
||||
updatePayload: {},
|
||||
type: string,
|
||||
oldProps: Props,
|
||||
newProps: Props,
|
||||
internalInstanceHandle: Object,
|
||||
): void {
|
||||
instance.type = type;
|
||||
instance.props = newProps;
|
||||
},
|
||||
|
||||
commitMount(
|
||||
instance: Instance,
|
||||
type: string,
|
||||
newProps: Props,
|
||||
internalInstanceHandle: Object,
|
||||
): void {
|
||||
// noop
|
||||
},
|
||||
|
||||
shouldSetTextContent(type: string, props: Props): boolean {
|
||||
return false;
|
||||
},
|
||||
|
||||
resetTextContent(testElement: Instance): void {
|
||||
// noop
|
||||
},
|
||||
|
||||
shouldDeprioritizeSubtree(type: string, props: Props): boolean {
|
||||
return false;
|
||||
},
|
||||
@@ -225,21 +200,6 @@ var TestRenderer = ReactFiberReconciler({
|
||||
};
|
||||
},
|
||||
|
||||
commitTextUpdate(
|
||||
textInstance: TextInstance,
|
||||
oldText: string,
|
||||
newText: string,
|
||||
): void {
|
||||
textInstance.text = newText;
|
||||
},
|
||||
|
||||
appendChild: appendChild,
|
||||
appendChildToContainer: appendChild,
|
||||
insertBefore: insertBefore,
|
||||
insertInContainerBefore: insertBefore,
|
||||
removeChild: removeChild,
|
||||
removeChildFromContainer: removeChild,
|
||||
|
||||
scheduleDeferredCallback(fn: Function): void {
|
||||
setTimeout(fn, 0, {timeRemaining: Infinity});
|
||||
},
|
||||
@@ -252,6 +212,47 @@ var TestRenderer = ReactFiberReconciler({
|
||||
// Test renderer does not use expiration
|
||||
return 0;
|
||||
},
|
||||
|
||||
mutation: {
|
||||
commitUpdate(
|
||||
instance: Instance,
|
||||
updatePayload: {},
|
||||
type: string,
|
||||
oldProps: Props,
|
||||
newProps: Props,
|
||||
internalInstanceHandle: Object,
|
||||
): void {
|
||||
instance.type = type;
|
||||
instance.props = newProps;
|
||||
},
|
||||
|
||||
commitMount(
|
||||
instance: Instance,
|
||||
type: string,
|
||||
newProps: Props,
|
||||
internalInstanceHandle: Object,
|
||||
): void {
|
||||
// noop
|
||||
},
|
||||
|
||||
commitTextUpdate(
|
||||
textInstance: TextInstance,
|
||||
oldText: string,
|
||||
newText: string,
|
||||
): void {
|
||||
textInstance.text = newText;
|
||||
},
|
||||
resetTextContent(testElement: Instance): void {
|
||||
// noop
|
||||
},
|
||||
|
||||
appendChild: appendChild,
|
||||
appendChildToContainer: appendChild,
|
||||
insertBefore: insertBefore,
|
||||
insertInContainerBefore: insertBefore,
|
||||
removeChild: removeChild,
|
||||
removeChildFromContainer: removeChild,
|
||||
},
|
||||
});
|
||||
|
||||
var defaultTestOptions = {
|
||||
|
||||
Reference in New Issue
Block a user