mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
45804af18d
<!-- Thanks for submitting a pull request! We appreciate you spending the time to work on these changes. Please provide enough information so that others can review your pull request. The three fields below are mandatory. Before submitting a pull request, please make sure the following is done: 1. Fork [the repository](https://github.com/facebook/react) and create your branch from `main`. 2. Run `yarn` in the repository root. 3. If you've fixed a bug or added code that should be tested, add tests! 4. Ensure the test suite passes (`yarn test`). Tip: `yarn test --watch TestName` is helpful in development. 5. Run `yarn test --prod` to test in the production environment. It supports the same options as `yarn test`. 6. If you need a debugger, run `yarn test --debug --watch TestName`, open `chrome://inspect`, and press "Inspect". 7. Format your code with [prettier](https://github.com/prettier/prettier) (`yarn prettier`). 8. Make sure your code lints (`yarn lint`). Tip: `yarn linc` to only check changed files. 9. Run the [Flow](https://flowtype.org/) type checks (`yarn flow`). 10. If you haven't already, complete the CLA. Learn more about contributing: https://reactjs.org/docs/how-to-contribute.html --> ## Summary In order to adopt react 19's ref-as-prop model, Flow needs to eliminate all the places where they are treated differently. `React.AbstractComponent` is the worst example of this, and we need to eliminate it. This PR eliminates them from the react repo, and only keeps the one that has 1 argument of props. ## How did you test this change? yarn flow
277 lines
8.8 KiB
JavaScript
277 lines
8.8 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,
|
|
getInternalInstanceHandleFromPublicInstance,
|
|
} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';
|
|
|
|
import {
|
|
findHostInstance,
|
|
findHostInstanceWithWarning,
|
|
} from 'react-reconciler/src/ReactFiberReconciler';
|
|
import {doesFiberContain} from 'react-reconciler/src/ReactFiberTreeReflection';
|
|
import getComponentNameFromType from 'shared/getComponentNameFromType';
|
|
import {
|
|
current as currentOwner,
|
|
isRendering,
|
|
} from 'react-reconciler/src/ReactCurrentFiber';
|
|
|
|
export function findHostInstance_DEPRECATED<TElementType: ElementType>(
|
|
componentOrHandle: ?(ElementRef<TElementType> | number),
|
|
): ?ElementRef<HostComponent<{...}>> {
|
|
if (__DEV__) {
|
|
const owner = currentOwner;
|
|
if (owner !== null && isRendering && 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 = currentOwner;
|
|
if (owner !== null && isRendering && 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) {
|
|
// $FlowFixMe[incompatible-return] Flow limitation in refining an opaque type
|
|
return hostInstance;
|
|
}
|
|
|
|
if (hostInstance._nativeTag != null) {
|
|
// $FlowFixMe[incompatible-return] For compatibility with legacy renderer instances
|
|
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
|
|
);
|
|
}
|
|
|
|
// Should have been PublicInstance from ReactFiberConfigFabric
|
|
type FabricPublicInstance = mixed;
|
|
// Should have been PublicInstance from ReactFiberConfigNative
|
|
type PaperPublicInstance = HostComponent<empty>;
|
|
|
|
// Remove this once Paper is no longer supported and DOM Node API are enabled by default in RN.
|
|
export function isChildPublicInstance(
|
|
parentInstance: FabricPublicInstance | PaperPublicInstance,
|
|
childInstance: FabricPublicInstance | PaperPublicInstance,
|
|
): boolean {
|
|
if (__DEV__) {
|
|
// Paper
|
|
if (
|
|
// $FlowExpectedError[incompatible-type]
|
|
// $FlowExpectedError[prop-missing] Don't check via `instanceof ReactNativeFiberHostComponent`, so it won't be leaked to Fabric.
|
|
parentInstance._internalFiberInstanceHandleDEV &&
|
|
// $FlowExpectedError[incompatible-type]
|
|
// $FlowExpectedError[prop-missing] Don't check via `instanceof ReactNativeFiberHostComponent`, so it won't be leaked to Fabric.
|
|
childInstance._internalFiberInstanceHandleDEV
|
|
) {
|
|
return doesFiberContain(
|
|
// $FlowExpectedError[incompatible-call]
|
|
parentInstance._internalFiberInstanceHandleDEV,
|
|
// $FlowExpectedError[incompatible-call]
|
|
childInstance._internalFiberInstanceHandleDEV,
|
|
);
|
|
}
|
|
|
|
const parentInternalInstanceHandle =
|
|
// $FlowExpectedError[incompatible-call] Type for parentInstance should have been PublicInstance from ReactFiberConfigFabric.
|
|
getInternalInstanceHandleFromPublicInstance(parentInstance);
|
|
const childInternalInstanceHandle =
|
|
// $FlowExpectedError[incompatible-call] Type for childInstance should have been PublicInstance from ReactFiberConfigFabric.
|
|
getInternalInstanceHandleFromPublicInstance(childInstance);
|
|
|
|
// Fabric
|
|
if (
|
|
parentInternalInstanceHandle != null &&
|
|
childInternalInstanceHandle != null
|
|
) {
|
|
return doesFiberContain(
|
|
parentInternalInstanceHandle,
|
|
childInternalInstanceHandle,
|
|
);
|
|
}
|
|
|
|
// Means that one instance is from Fabric and other is from Paper.
|
|
return false;
|
|
} else {
|
|
throw new Error('isChildPublicInstance() is not available in production.');
|
|
}
|
|
}
|