react-native-macos
Version:
A framework for building native macOS apps using React
272 lines (233 loc) • 7.79 kB
JavaScript
/**
* Copyright 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule ReactFiberReconciler
* @flow
*/
'use strict';
import type {Fiber} from 'ReactFiber';
import type {FiberRoot} from 'ReactFiberRoot';
import type {PriorityLevel} from 'ReactPriorityLevel';
import type {ReactNodeList} from 'ReactTypes';
var ReactFeatureFlags = require('ReactFeatureFlags');
var {addTopLevelUpdate} = require('ReactFiberUpdateQueue');
var {
findCurrentUnmaskedContext,
isContextProvider,
processChildContext,
} = require('ReactFiberContext');
var {createFiberRoot} = require('ReactFiberRoot');
var ReactFiberScheduler = require('ReactFiberScheduler');
if (__DEV__) {
var warning = require('fbjs/lib/warning');
var ReactFiberInstrumentation = require('ReactFiberInstrumentation');
var ReactDebugCurrentFiber = require('ReactDebugCurrentFiber');
var getComponentName = require('getComponentName');
}
var {findCurrentHostFiber} = require('ReactFiberTreeReflection');
var getContextForSubtree = require('getContextForSubtree');
export type Deadline = {
timeRemaining: () => number,
};
type OpaqueHandle = Fiber;
type OpaqueRoot = FiberRoot;
export type HostConfig<T, P, I, TI, PI, C, CX, PL> = {
getRootHostContext(rootContainerInstance: C): CX,
getChildHostContext(parentHostContext: CX, type: T): CX,
getPublicInstance(instance: I | TI): PI,
createInstance(
type: T,
props: P,
rootContainerInstance: C,
hostContext: CX,
internalInstanceHandle: OpaqueHandle,
): I,
appendInitialChild(parentInstance: I, child: I | TI): void,
finalizeInitialChildren(
parentInstance: I,
type: T,
props: P,
rootContainerInstance: C,
): boolean,
prepareUpdate(
instance: I,
type: T,
oldProps: P,
newProps: P,
rootContainerInstance: C,
hostContext: CX,
): null | PL,
commitUpdate(
instance: I,
updatePayload: PL,
type: T,
oldProps: P,
newProps: P,
internalInstanceHandle: OpaqueHandle,
): void,
commitMount(
instance: I,
type: T,
newProps: P,
internalInstanceHandle: OpaqueHandle,
): void,
shouldSetTextContent(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,
appendChild(parentInstance: I | C, child: I | TI): void,
insertBefore(parentInstance: I | C, child: I | TI, beforeChild: I | TI): void,
removeChild(parentInstance: I | C, child: I | TI): void,
scheduleAnimationCallback(callback: () => void): number | void,
scheduleDeferredCallback(
callback: (deadline: Deadline) => void,
): number | void,
prepareForCommit(): void,
resetAfterCommit(): void,
useSyncScheduling?: boolean,
};
export type Reconciler<C, I, TI> = {
createContainer(containerInfo: C): OpaqueRoot,
updateContainer(
element: ReactNodeList,
container: OpaqueRoot,
parentComponent: ?ReactComponent<any, any, any>,
callback: ?Function,
): void,
performWithPriority(priorityLevel: PriorityLevel, fn: Function): void,
batchedUpdates<A>(fn: () => A): A,
unbatchedUpdates<A>(fn: () => A): A,
syncUpdates<A>(fn: () => A): A,
deferredUpdates<A>(fn: () => A): A,
// Used to extract the return value from the initial render. Legacy API.
getPublicRootInstance(
container: OpaqueRoot,
): ReactComponent<any, any, any> | TI | I | null,
// Use for findDOMNode/findHostNode. Legacy API.
findHostInstance(component: Fiber): I | TI | null,
};
getContextForSubtree._injectFiber(function(fiber: Fiber) {
const parentContext = findCurrentUnmaskedContext(fiber);
return isContextProvider(fiber)
? processChildContext(fiber, parentContext, false)
: parentContext;
});
module.exports = function<T, P, I, TI, PI, C, CX, PL>(
config: HostConfig<T, P, I, TI, PI, C, CX, PL>,
): Reconciler<C, I, TI> {
var {
scheduleUpdate,
getPriorityContext,
performWithPriority,
batchedUpdates,
unbatchedUpdates,
syncUpdates,
deferredUpdates,
} = ReactFiberScheduler(config);
function scheduleTopLevelUpdate(
current: Fiber,
element: ReactNodeList,
callback: ?Function,
) {
if (__DEV__) {
if (
ReactDebugCurrentFiber.phase === 'render' &&
ReactDebugCurrentFiber.current !== null
) {
warning(
false,
'Render methods should be a pure function of props and state; ' +
'triggering nested component updates from render is not allowed. ' +
'If necessary, trigger nested updates in componentDidUpdate.\n\n' +
'Check the render method of %s.',
getComponentName(ReactDebugCurrentFiber.current) || 'Unknown',
);
}
}
// Check if the top-level element is an async wrapper component. If so, treat
// updates to the root as async. This is a bit weird but lets us avoid a separate
// `renderAsync` API.
const forceAsync =
(ReactFeatureFlags : any).enableAsyncSubtreeAPI &&
element != null &&
element.type != null &&
(element.type: any).unstable_asyncUpdates === true;
const priorityLevel = getPriorityContext(current, forceAsync);
const nextState = {element};
callback = callback === undefined ? null : callback;
if (__DEV__) {
warning(
callback === null || typeof callback === 'function',
'render(...): Expected the last optional `callback` argument to be a ' +
'function. Instead received: %s.',
callback,
);
}
addTopLevelUpdate(current, nextState, callback, priorityLevel);
scheduleUpdate(current, priorityLevel);
}
return {
createContainer(containerInfo: C): OpaqueRoot {
return createFiberRoot(containerInfo);
},
updateContainer(
element: ReactNodeList,
container: OpaqueRoot,
parentComponent: ?ReactComponent<any, any, any>,
callback: ?Function,
): void {
// TODO: If this is a nested container, this won't be the root.
const current = container.current;
if (__DEV__) {
if (ReactFiberInstrumentation.debugTool) {
if (current.alternate === null) {
ReactFiberInstrumentation.debugTool.onMountContainer(container);
} else if (element === null) {
ReactFiberInstrumentation.debugTool.onUnmountContainer(container);
} else {
ReactFiberInstrumentation.debugTool.onUpdateContainer(container);
}
}
}
const context = getContextForSubtree(parentComponent);
if (container.context === null) {
container.context = context;
} else {
container.pendingContext = context;
}
scheduleTopLevelUpdate(current, element, callback);
},
performWithPriority,
batchedUpdates,
unbatchedUpdates,
syncUpdates,
deferredUpdates,
getPublicRootInstance(
container: OpaqueRoot,
): ReactComponent<any, any, any> | I | TI | null {
const containerFiber = container.current;
if (!containerFiber.child) {
return null;
}
return containerFiber.child.stateNode;
},
findHostInstance(fiber: Fiber): I | TI | null {
const hostFiber = findCurrentHostFiber(fiber);
if (hostFiber === null) {
return null;
}
return hostFiber.stateNode;
},
};
};