mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
9c54b29b44
## Summary Now that React Native owns the definition for public instances in Fabric and ReactNativePrivateInterface provides the methods to create instances and access private fields (see https://github.com/facebook/react-native/pull/36570), we can remove the definitions from React. After this PR, React Native public instances will be opaque types for React and it will only handle their creation but not their definition. This will make RN similar to DOM in how public instances are handled. This is a new version of #26418 which was closed without merging. ## How did you test this change? * Existing tests. * Manually synced the changes in this PR to React Native and tested it end to end in Meta's infra.
220 lines
6.5 KiB
JavaScript
220 lines
6.5 KiB
JavaScript
/**
|
|
* 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.
|
|
*
|
|
* @flow
|
|
*/
|
|
|
|
import type {Node, HostComponent} from './ReactNativeTypes';
|
|
import type {ElementRef, ElementType} from 'react';
|
|
|
|
// Modules provided by RN:
|
|
import {
|
|
UIManager,
|
|
legacySendAccessibilityEvent,
|
|
getNodeFromPublicInstance,
|
|
getNativeTagFromPublicInstance,
|
|
} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';
|
|
|
|
import {
|
|
findHostInstance,
|
|
findHostInstanceWithWarning,
|
|
} from 'react-reconciler/src/ReactFiberReconciler';
|
|
import ReactSharedInternals from 'shared/ReactSharedInternals';
|
|
import getComponentNameFromType from 'shared/getComponentNameFromType';
|
|
|
|
const ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner;
|
|
|
|
export function findHostInstance_DEPRECATED<TElementType: ElementType>(
|
|
componentOrHandle: ?(ElementRef<TElementType> | number),
|
|
): ?ElementRef<HostComponent<mixed>> {
|
|
if (__DEV__) {
|
|
const owner = ReactCurrentOwner.current;
|
|
if (owner !== null && owner.stateNode !== null) {
|
|
if (!owner.stateNode._warnedAboutRefsInRender) {
|
|
console.error(
|
|
'%s is accessing findNodeHandle inside its render(). ' +
|
|
'render() should be a pure function of props and state. It should ' +
|
|
'never access something that requires stale data from the previous ' +
|
|
'render, such as refs. Move this logic to componentDidMount and ' +
|
|
'componentDidUpdate instead.',
|
|
getComponentNameFromType(owner.type) || 'A component',
|
|
);
|
|
}
|
|
|
|
owner.stateNode._warnedAboutRefsInRender = true;
|
|
}
|
|
}
|
|
|
|
if (componentOrHandle == null) {
|
|
return null;
|
|
}
|
|
|
|
// For compatibility with Fabric instances
|
|
if (
|
|
componentOrHandle.canonical &&
|
|
componentOrHandle.canonical.publicInstance
|
|
) {
|
|
// $FlowExpectedError[incompatible-return] Can't refine componentOrHandle as a Fabric instance
|
|
return componentOrHandle.canonical.publicInstance;
|
|
}
|
|
|
|
// For compatibility with legacy renderer instances
|
|
if (componentOrHandle._nativeTag) {
|
|
// $FlowFixMe[incompatible-exact] Necessary when running Flow on Fabric
|
|
// $FlowFixMe[incompatible-return]
|
|
return componentOrHandle;
|
|
}
|
|
|
|
let hostInstance;
|
|
if (__DEV__) {
|
|
hostInstance = findHostInstanceWithWarning(
|
|
componentOrHandle,
|
|
'findHostInstance_DEPRECATED',
|
|
);
|
|
} else {
|
|
hostInstance = findHostInstance(componentOrHandle);
|
|
}
|
|
|
|
// findHostInstance handles legacy vs. Fabric differences correctly
|
|
// $FlowFixMe[incompatible-exact] we need to fix the definition of `HostComponent` to use NativeMethods as an interface, not as a type.
|
|
// $FlowFixMe[incompatible-return]
|
|
return hostInstance;
|
|
}
|
|
|
|
export function findNodeHandle(componentOrHandle: any): ?number {
|
|
if (__DEV__) {
|
|
const owner = ReactCurrentOwner.current;
|
|
if (owner !== null && owner.stateNode !== null) {
|
|
if (!owner.stateNode._warnedAboutRefsInRender) {
|
|
console.error(
|
|
'%s is accessing findNodeHandle inside its render(). ' +
|
|
'render() should be a pure function of props and state. It should ' +
|
|
'never access something that requires stale data from the previous ' +
|
|
'render, such as refs. Move this logic to componentDidMount and ' +
|
|
'componentDidUpdate instead.',
|
|
getComponentNameFromType(owner.type) || 'A component',
|
|
);
|
|
}
|
|
|
|
owner.stateNode._warnedAboutRefsInRender = true;
|
|
}
|
|
}
|
|
|
|
if (componentOrHandle == null) {
|
|
return null;
|
|
}
|
|
|
|
if (typeof componentOrHandle === 'number') {
|
|
// Already a node handle
|
|
return componentOrHandle;
|
|
}
|
|
|
|
// For compatibility with legacy renderer instances
|
|
if (componentOrHandle._nativeTag) {
|
|
return componentOrHandle._nativeTag;
|
|
}
|
|
|
|
// For compatibility with Fabric instances
|
|
if (
|
|
componentOrHandle.canonical != null &&
|
|
componentOrHandle.canonical.nativeTag != null
|
|
) {
|
|
return componentOrHandle.canonical.nativeTag;
|
|
}
|
|
|
|
// For compatibility with Fabric public instances
|
|
const nativeTag = getNativeTagFromPublicInstance(componentOrHandle);
|
|
if (nativeTag) {
|
|
return nativeTag;
|
|
}
|
|
|
|
let hostInstance;
|
|
if (__DEV__) {
|
|
hostInstance = findHostInstanceWithWarning(
|
|
componentOrHandle,
|
|
'findNodeHandle',
|
|
);
|
|
} else {
|
|
hostInstance = findHostInstance(componentOrHandle);
|
|
}
|
|
|
|
if (hostInstance == null) {
|
|
return hostInstance;
|
|
}
|
|
|
|
// $FlowFixMe[incompatible-type] For compatibility with legacy renderer instances
|
|
if (hostInstance._nativeTag != null) {
|
|
return hostInstance._nativeTag;
|
|
}
|
|
|
|
// $FlowFixMe[incompatible-call] Necessary when running Flow on the legacy renderer
|
|
return getNativeTagFromPublicInstance(hostInstance);
|
|
}
|
|
|
|
export function dispatchCommand(
|
|
handle: any,
|
|
command: string,
|
|
args: Array<any>,
|
|
) {
|
|
const nativeTag =
|
|
handle._nativeTag != null
|
|
? handle._nativeTag
|
|
: getNativeTagFromPublicInstance(handle);
|
|
if (nativeTag == null) {
|
|
if (__DEV__) {
|
|
console.error(
|
|
"dispatchCommand was called with a ref that isn't a " +
|
|
'native component. Use React.forwardRef to get access to the underlying native component',
|
|
);
|
|
}
|
|
return;
|
|
}
|
|
|
|
const node = getNodeFromPublicInstance(handle);
|
|
|
|
if (node != null) {
|
|
nativeFabricUIManager.dispatchCommand(node, command, args);
|
|
} else {
|
|
UIManager.dispatchViewManagerCommand(nativeTag, command, args);
|
|
}
|
|
}
|
|
|
|
export function sendAccessibilityEvent(handle: any, eventType: string) {
|
|
const nativeTag =
|
|
handle._nativeTag != null
|
|
? handle._nativeTag
|
|
: getNativeTagFromPublicInstance(handle);
|
|
if (nativeTag == null) {
|
|
if (__DEV__) {
|
|
console.error(
|
|
"sendAccessibilityEvent was called with a ref that isn't a " +
|
|
'native component. Use React.forwardRef to get access to the underlying native component',
|
|
);
|
|
}
|
|
return;
|
|
}
|
|
|
|
const node = getNodeFromPublicInstance(handle);
|
|
if (node != null) {
|
|
nativeFabricUIManager.sendAccessibilityEvent(node, eventType);
|
|
} else {
|
|
legacySendAccessibilityEvent(nativeTag, eventType);
|
|
}
|
|
}
|
|
|
|
export function getNodeFromInternalInstanceHandle(
|
|
internalInstanceHandle: mixed,
|
|
): ?Node {
|
|
return (
|
|
// $FlowExpectedError[incompatible-return] internalInstanceHandle is opaque but we need to make an exception here.
|
|
internalInstanceHandle &&
|
|
// $FlowExpectedError[incompatible-return]
|
|
internalInstanceHandle.stateNode &&
|
|
// $FlowExpectedError[incompatible-use]
|
|
internalInstanceHandle.stateNode.node
|
|
);
|
|
}
|