mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Extract use of renderer to its own module
Summary: This diff creates a proxy module to interact with the React Native renderer. The goal of this proxy is to decouple usages of several functions (e.g.: `findNodeHandle`, etc.) from the actual renderer used in an app. This way, we can easily switch between renderers without having to change code depending on it. This will be useful to remove a specific renderer from an app bundle when it's no longer used (e.g.: Paper on the Facebook App). Changelog: [Internal] Reviewed By: javache Differential Revision: D39205975 fbshipit-source-id: 05289c0c3c8cd26d81aa1d2163097c73ec40c6ad
This commit is contained in:
committed by
Facebook GitHub Bot
parent
5efb4f09fd
commit
b06cae3681
@@ -8,22 +8,21 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
const BatchedBridge = require('../BatchedBridge/BatchedBridge');
|
||||
const BugReporting = require('../BugReporting/BugReporting');
|
||||
const ReactNative = require('../Renderer/shims/ReactNative');
|
||||
const SceneTracker = require('../Utilities/SceneTracker');
|
||||
|
||||
const infoLog = require('../Utilities/infoLog');
|
||||
const invariant = require('invariant');
|
||||
const renderApplication = require('./renderApplication');
|
||||
import type {IPerformanceLogger} from '../Utilities/createPerformanceLogger';
|
||||
|
||||
import {coerceDisplayMode} from './DisplayMode';
|
||||
import createPerformanceLogger from '../Utilities/createPerformanceLogger';
|
||||
import NativeHeadlessJsTaskSupport from './NativeHeadlessJsTaskSupport';
|
||||
import HeadlessJsTaskError from './HeadlessJsTaskError';
|
||||
import type {RootTag} from 'react-native/Libraries/Types/RootTagTypes';
|
||||
|
||||
import BatchedBridge from '../BatchedBridge/BatchedBridge';
|
||||
import BugReporting from '../BugReporting/BugReporting';
|
||||
import createPerformanceLogger from '../Utilities/createPerformanceLogger';
|
||||
import infoLog from '../Utilities/infoLog';
|
||||
import SceneTracker from '../Utilities/SceneTracker';
|
||||
import {coerceDisplayMode} from './DisplayMode';
|
||||
import HeadlessJsTaskError from './HeadlessJsTaskError';
|
||||
import NativeHeadlessJsTaskSupport from './NativeHeadlessJsTaskSupport';
|
||||
import {unmountComponentAtNodeAndRemoveContainer} from './RendererProxy';
|
||||
import renderApplication from './renderApplication';
|
||||
import invariant from 'invariant';
|
||||
|
||||
type Task = (taskData: any) => Promise<void>;
|
||||
export type TaskProvider = () => Task;
|
||||
type TaskCanceller = () => void;
|
||||
@@ -250,9 +249,7 @@ const AppRegistry = {
|
||||
* See https://reactnative.dev/docs/appregistry#unmountapplicationcomponentatroottag
|
||||
*/
|
||||
unmountApplicationComponentAtRootTag(rootTag: RootTag): void {
|
||||
// NOTE: RootTag type
|
||||
// $FlowFixMe[incompatible-call] RootTag: RootTag is incompatible with number, needs an updated synced version of the ReactNativeTypes.js file
|
||||
ReactNative.unmountComponentAtNodeAndRemoveContainer(rootTag);
|
||||
unmountComponentAtNodeAndRemoveContainer(rootTag);
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
* @flow strict-local
|
||||
*/
|
||||
|
||||
import {type RootTag} from './RootTag';
|
||||
import type {Element, ElementType, ElementRef} from 'react';
|
||||
import type {HostComponent} from '../Renderer/shims/ReactNativeTypes';
|
||||
|
||||
export function renderElement({
|
||||
element,
|
||||
rootTag,
|
||||
useFabric,
|
||||
useConcurrentRoot,
|
||||
}: {
|
||||
element: Element<ElementType>,
|
||||
rootTag: number,
|
||||
useFabric: boolean,
|
||||
useConcurrentRoot: boolean,
|
||||
}): void {
|
||||
if (useFabric) {
|
||||
require('../Renderer/shims/ReactFabric').render(
|
||||
element,
|
||||
rootTag,
|
||||
null,
|
||||
useConcurrentRoot,
|
||||
);
|
||||
} else {
|
||||
require('../Renderer/shims/ReactNative').render(element, rootTag);
|
||||
}
|
||||
}
|
||||
|
||||
export function findHostInstance_DEPRECATED<TElementType: ElementType>(
|
||||
componentOrHandle: ?(ElementRef<TElementType> | number),
|
||||
): ?ElementRef<HostComponent<mixed>> {
|
||||
return require('../Renderer/shims/ReactNative').findHostInstance_DEPRECATED(
|
||||
componentOrHandle,
|
||||
);
|
||||
}
|
||||
|
||||
export function findNodeHandle<TElementType: ElementType>(
|
||||
componentOrHandle: ?(ElementRef<TElementType> | number),
|
||||
): ?number {
|
||||
return require('../Renderer/shims/ReactNative').findNodeHandle(
|
||||
componentOrHandle,
|
||||
);
|
||||
}
|
||||
|
||||
export function dispatchCommand(
|
||||
handle: ElementRef<HostComponent<mixed>>,
|
||||
command: string,
|
||||
args: Array<mixed>,
|
||||
): void {
|
||||
if (global.RN$Bridgeless === true) {
|
||||
// Note: this function has the same implementation in the legacy and new renderer.
|
||||
// However, evaluating the old renderer comes with some side effects.
|
||||
return require('../Renderer/shims/ReactFabric').dispatchCommand(
|
||||
handle,
|
||||
command,
|
||||
args,
|
||||
);
|
||||
} else {
|
||||
return require('../Renderer/shims/ReactNative').dispatchCommand(
|
||||
handle,
|
||||
command,
|
||||
args,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function sendAccessibilityEvent(
|
||||
handle: ElementRef<HostComponent<mixed>>,
|
||||
eventType: string,
|
||||
): void {
|
||||
return require('../Renderer/shims/ReactNative').sendAccessibilityEvent(
|
||||
handle,
|
||||
eventType,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used by AppRegistry to unmount a root when using the old
|
||||
* React Native renderer (Paper).
|
||||
*/
|
||||
export function unmountComponentAtNodeAndRemoveContainer(rootTag: RootTag) {
|
||||
// $FlowExpectedError[incompatible-type] rootTag is an opaque type so we can't really cast it as is.
|
||||
const rootTagAsNumber: number = rootTag;
|
||||
require('../Renderer/shims/ReactNative').unmountComponentAtNodeAndRemoveContainer(
|
||||
rootTagAsNumber,
|
||||
);
|
||||
}
|
||||
|
||||
export function unstable_batchedUpdates<T>(
|
||||
fn: T => void,
|
||||
bookkeeping: T,
|
||||
): void {
|
||||
// This doesn't actually do anything when batching updates for a Fabric root.
|
||||
return require('../Renderer/shims/ReactNative').unstable_batchedUpdates(
|
||||
fn,
|
||||
bookkeeping,
|
||||
);
|
||||
}
|
||||
|
||||
export function isProfilingRenderer(): boolean {
|
||||
return Boolean(__DEV__);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
* @flow strict-local
|
||||
*/
|
||||
|
||||
/**
|
||||
* This module exists to allow apps to select their renderer implementation
|
||||
* (e.g.: Fabric-only, Paper-only) without having to pull all the renderer
|
||||
* implementations into their app bundle, which affects app size.
|
||||
*
|
||||
* By default, the setup will be:
|
||||
* -> RendererProxy
|
||||
* -> RendererImplementation (which uses Fabric or Paper depending on a flag at runtime)
|
||||
*
|
||||
* But this will allow a setup like this without duplicating logic:
|
||||
* -> RendererProxy (fork)
|
||||
* -> RendererImplementation (which uses Fabric or Paper depending on a flag at runtime)
|
||||
* or -> OtherImplementation (which uses Fabric only)
|
||||
*/
|
||||
|
||||
export * from './RendererImplementation';
|
||||
@@ -8,20 +8,21 @@
|
||||
* @flow
|
||||
*/
|
||||
|
||||
const AppContainer = require('./AppContainer');
|
||||
import GlobalPerformanceLogger from '../Utilities/GlobalPerformanceLogger';
|
||||
import type {IPerformanceLogger} from '../Utilities/createPerformanceLogger';
|
||||
import PerformanceLoggerContext from '../Utilities/PerformanceLoggerContext';
|
||||
import type {DisplayModeType} from './DisplayMode';
|
||||
import getCachedComponentWithDebugName from './getCachedComponentWithDebugName';
|
||||
const React = require('react');
|
||||
|
||||
const invariant = require('invariant');
|
||||
import GlobalPerformanceLogger from '../Utilities/GlobalPerformanceLogger';
|
||||
import PerformanceLoggerContext from '../Utilities/PerformanceLoggerContext';
|
||||
import AppContainer from './AppContainer';
|
||||
import getCachedComponentWithDebugName from './getCachedComponentWithDebugName';
|
||||
import * as Renderer from './RendererProxy';
|
||||
import invariant from 'invariant';
|
||||
import * as React from 'react';
|
||||
|
||||
// require BackHandler so it sets the default handler that exits the app if no listeners respond
|
||||
require('../Utilities/BackHandler');
|
||||
import '../Utilities/BackHandler';
|
||||
|
||||
function renderApplication<Props: Object>(
|
||||
export default function renderApplication<Props: Object>(
|
||||
RootComponent: React.ComponentType<Props>,
|
||||
initialProps: Props,
|
||||
rootTag: any,
|
||||
@@ -69,17 +70,15 @@ function renderApplication<Props: Object>(
|
||||
useConcurrentRoot ? '1' : '0',
|
||||
);
|
||||
performanceLogger.setExtra('usedReactFabric', fabric ? '1' : '0');
|
||||
if (fabric) {
|
||||
require('../Renderer/shims/ReactFabric').render(
|
||||
renderable,
|
||||
rootTag,
|
||||
null,
|
||||
useConcurrentRoot,
|
||||
);
|
||||
} else {
|
||||
require('../Renderer/shims/ReactNative').render(renderable, rootTag);
|
||||
}
|
||||
performanceLogger.setExtra(
|
||||
'usedReactProfiler',
|
||||
Renderer.isProfilingRenderer(),
|
||||
);
|
||||
Renderer.renderElement({
|
||||
element: renderable,
|
||||
rootTag,
|
||||
useFabric: Boolean(fabric),
|
||||
useConcurrentRoot: Boolean(useConcurrentRoot),
|
||||
});
|
||||
performanceLogger.stopTimespan('renderApplication_React_render');
|
||||
}
|
||||
|
||||
module.exports = renderApplication;
|
||||
|
||||
@@ -10,14 +10,13 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
const BatchedBridge = require('react-native/Libraries/BatchedBridge/BatchedBridge');
|
||||
const React = require('react');
|
||||
|
||||
const renderApplication = require('react-native/Libraries/ReactNative/renderApplication');
|
||||
|
||||
const {StyleSheet, Text, View} = require('react-native');
|
||||
import type {RootTag} from 'react-native/Libraries/Types/RootTagTypes';
|
||||
|
||||
import * as React from 'react';
|
||||
import {StyleSheet, Text, View} from 'react-native';
|
||||
import BatchedBridge from 'react-native/Libraries/BatchedBridge/BatchedBridge';
|
||||
import renderApplication from 'react-native/Libraries/ReactNative/renderApplication';
|
||||
|
||||
type FlexTestAppProps = $ReadOnly<{||}>;
|
||||
class FlexTestApp extends React.Component<FlexTestAppProps> {
|
||||
render(): React.Node {
|
||||
@@ -267,4 +266,4 @@ BatchedBridge.registerCallableModule(
|
||||
UIManagerTestModule,
|
||||
);
|
||||
|
||||
module.exports = UIManagerTestModule;
|
||||
export default UIManagerTestModule;
|
||||
|
||||
@@ -282,7 +282,7 @@ module.exports = {
|
||||
return require('./Libraries/Animated/Easing');
|
||||
},
|
||||
get findNodeHandle(): $PropertyType<ReactNative, 'findNodeHandle'> {
|
||||
return require('./Libraries/Renderer/shims/ReactNative').findNodeHandle;
|
||||
return require('./Libraries/ReactNative/RendererProxy').findNodeHandle;
|
||||
},
|
||||
get I18nManager(): I18nManager {
|
||||
return require('./Libraries/ReactNative/I18nManager');
|
||||
@@ -366,7 +366,7 @@ module.exports = {
|
||||
ReactNative,
|
||||
'unstable_batchedUpdates',
|
||||
> {
|
||||
return require('./Libraries/Renderer/shims/ReactNative')
|
||||
return require('./Libraries/ReactNative/RendererProxy')
|
||||
.unstable_batchedUpdates;
|
||||
},
|
||||
get useColorScheme(): useColorScheme {
|
||||
|
||||
Reference in New Issue
Block a user