diff --git a/Libraries/ReactNative/AppRegistry.js b/Libraries/ReactNative/AppRegistry.js index 6607db3954a708..cb494e15f15482 100644 --- a/Libraries/ReactNative/AppRegistry.js +++ b/Libraries/ReactNative/AppRegistry.js @@ -8,21 +8,20 @@ * @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 type {RootTag} from 'react-native/Libraries/Types/RootTagTypes'; -import {coerceDisplayMode} from './DisplayMode'; +import BatchedBridge from '../BatchedBridge/BatchedBridge'; +import BugReporting from '../BugReporting/BugReporting'; import createPerformanceLogger from '../Utilities/createPerformanceLogger'; -import NativeHeadlessJsTaskSupport from './NativeHeadlessJsTaskSupport'; +import infoLog from '../Utilities/infoLog'; +import SceneTracker from '../Utilities/SceneTracker'; +import {coerceDisplayMode} from './DisplayMode'; import HeadlessJsTaskError from './HeadlessJsTaskError'; -import type {RootTag} from 'react-native/Libraries/Types/RootTagTypes'; +import NativeHeadlessJsTaskSupport from './NativeHeadlessJsTaskSupport'; +import {unmountComponentAtNodeAndRemoveContainer} from './RendererProxy'; +import renderApplication from './renderApplication'; +import invariant from 'invariant'; type Task = (taskData: any) => Promise; export type TaskProvider = () => Task; @@ -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); }, /** diff --git a/Libraries/ReactNative/RendererImplementation.js b/Libraries/ReactNative/RendererImplementation.js new file mode 100644 index 00000000000000..08614d08ac5705 --- /dev/null +++ b/Libraries/ReactNative/RendererImplementation.js @@ -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, + 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( + componentOrHandle: ?(ElementRef | number), +): ?ElementRef> { + return require('../Renderer/shims/ReactNative').findHostInstance_DEPRECATED( + componentOrHandle, + ); +} + +export function findNodeHandle( + componentOrHandle: ?(ElementRef | number), +): ?number { + return require('../Renderer/shims/ReactNative').findNodeHandle( + componentOrHandle, + ); +} + +export function dispatchCommand( + handle: ElementRef>, + command: string, + args: Array, +): 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>, + 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( + 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__); +} diff --git a/Libraries/ReactNative/RendererProxy.js b/Libraries/ReactNative/RendererProxy.js new file mode 100644 index 00000000000000..6698e0f68c37e6 --- /dev/null +++ b/Libraries/ReactNative/RendererProxy.js @@ -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'; diff --git a/Libraries/ReactNative/renderApplication.js b/Libraries/ReactNative/renderApplication.js index 2e701dcbac5399..3568d4d0fa7d26 100644 --- a/Libraries/ReactNative/renderApplication.js +++ b/Libraries/ReactNative/renderApplication.js @@ -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( +export default function renderApplication( RootComponent: React.ComponentType, initialProps: Props, rootTag: any, @@ -69,17 +70,15 @@ function renderApplication( 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; diff --git a/ReactAndroid/src/androidTest/js/UIManagerTestModule.js b/ReactAndroid/src/androidTest/js/UIManagerTestModule.js index 658953786a90a1..9433f36b786538 100644 --- a/ReactAndroid/src/androidTest/js/UIManagerTestModule.js +++ b/ReactAndroid/src/androidTest/js/UIManagerTestModule.js @@ -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 { render(): React.Node { @@ -267,4 +266,4 @@ BatchedBridge.registerCallableModule( UIManagerTestModule, ); -module.exports = UIManagerTestModule; +export default UIManagerTestModule; diff --git a/index.js b/index.js index 0db5984da43e77..6f71b4e073ab71 100644 --- a/index.js +++ b/index.js @@ -282,7 +282,7 @@ module.exports = { return require('./Libraries/Animated/Easing'); }, get findNodeHandle(): $PropertyType { - 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 {