RN: Delete setAndForwardRefs

Summary:
Deletes `setAndForwardRefs` because it encourages a subtle pitfall with managing the referential equality of `ref` entities.

By the time this commit is landed, there will have been no more call sites to it in the `facebook/react-native` repository.

Changelog:
[Internal]

Reviewed By: sammy-SC

Differential Revision: D41209331

fbshipit-source-id: 3ef9c3543b581a716a1e41e524957867ee811675
This commit is contained in:
Tim Yung
2022-11-14 08:50:22 -08:00
committed by Facebook GitHub Bot
parent 7cf4cf3afb
commit bf6ed07c0f
2 changed files with 0 additions and 209 deletions
@@ -1,138 +0,0 @@
/**
* 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
* @format
* @oncall react_native
*/
'use strict';
const setAndForwardRef = require('../setAndForwardRef');
const React = require('react');
const ReactTestRenderer = require('react-test-renderer');
describe('setAndForwardRef', () => {
let innerFuncCalled: ?boolean = false;
let outerFuncCalled: ?boolean = false;
class ForwardedComponent extends React.Component<{||}> {
testFunc(): any {
innerFuncCalled = true;
return true;
}
render(): any {
return null;
}
}
type Props = $ReadOnly<{|
callFunc?: ?boolean,
forwardedRef: React.Ref<typeof ForwardedComponent>,
|}>;
class TestComponent extends React.Component<Props> {
_nativeRef: ?React.ElementRef<typeof ForwardedComponent> = null;
_setNativeRef: (ref: React.ElementRef<any>) => void = setAndForwardRef({
getForwardedRef: () => this.props.forwardedRef,
setLocalRef: ref => {
this._nativeRef = ref;
},
});
componentDidMount() {
if (this.props.callFunc) {
outerFuncCalled = this._nativeRef && this._nativeRef.testFunc();
}
}
render(): React.Node {
return <ForwardedComponent ref={this._setNativeRef} />;
}
}
const TestComponentWithRef = React.forwardRef((props, ref) => (
<TestComponent {...props} forwardedRef={ref} />
));
beforeEach(() => {
innerFuncCalled = false;
outerFuncCalled = false;
});
it('should forward refs (function-based)', () => {
let testRef: ?React.ElementRef<typeof ForwardedComponent> = null;
ReactTestRenderer.create(
<TestComponentWithRef
ref={ref => {
testRef = ref;
}}
/>,
);
const val = testRef && testRef.testFunc();
expect(innerFuncCalled).toBe(true);
expect(val).toBe(true);
});
it('should forward refs (createRef-based)', () => {
const createdRef = React.createRef<typeof ForwardedComponent>();
/* $FlowFixMe[incompatible-type] (>=0.89.0 site=react_native_fb) This
* comment suppresses an error found when Flow v0.89 was deployed. To see
* the error, delete this comment and run Flow. */
ReactTestRenderer.create(<TestComponentWithRef ref={createdRef} />);
/* $FlowFixMe[prop-missing] (>=0.87.0 site=react_native_fb) This comment
* suppresses an error found when Flow v0.87 was deployed. To see the
* error, delete this comment and run Flow. */
const val = createdRef.current && createdRef.current.testFunc();
expect(innerFuncCalled).toBe(true);
expect(val).toBe(true);
});
it('should forward refs (string-based)', () => {
class Test extends React.Component<{||}> {
refs: $ReadOnly<{|
stringRef?: ?React.ElementRef<typeof ForwardedComponent>,
|}>;
componentDidMount() {
/* eslint-disable react/no-string-refs */
this.refs.stringRef && this.refs.stringRef.testFunc();
/* eslint-enable react/no-string-refs */
}
render(): React.Node {
/**
* Can't directly pass the test component to `ReactTestRenderer.create`,
* otherwise it will throw. See:
* https://reactjs.org/warnings/refs-must-have-owner.html#strings-refs-outside-the-render-method
*/
/* eslint-disable react/no-string-refs */
return <TestComponentWithRef ref="stringRef" />;
/* eslint-enable react/no-string-refs */
}
}
ReactTestRenderer.create(<Test />);
expect(innerFuncCalled).toBe(true);
});
it('should be able to use the ref from inside of the forwarding class', () => {
expect(() =>
ReactTestRenderer.create(<TestComponentWithRef callFunc={true} />),
).not.toThrow();
expect(innerFuncCalled).toBe(true);
expect(outerFuncCalled).toBe(true);
});
});
-71
View File
@@ -1,71 +0,0 @@
/**
* 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
*/
'use strict';
import type {ElementRef, Ref} from 'react';
type Args = $ReadOnly<{|
getForwardedRef: () => ?Ref<any>,
setLocalRef: (ref: ElementRef<any>) => mixed,
|}>;
/**
* This is a helper function for when a component needs to be able to forward a ref
* to a child component, but still needs to have access to that component as part of
* its implementation.
*
* Its main use case is in wrappers for native components.
*
* Usage:
*
* class MyView extends React.Component {
* _nativeRef = null;
*
* _setNativeRef = setAndForwardRef({
* getForwardedRef: () => this.props.forwardedRef,
* setLocalRef: ref => {
* this._nativeRef = ref;
* },
* });
*
* render() {
* return <View ref={this._setNativeRef} />;
* }
* }
*
* const MyViewWithRef = React.forwardRef((props, ref) => (
* <MyView {...props} forwardedRef={ref} />
* ));
*
* module.exports = MyViewWithRef;
*/
function setAndForwardRef({
getForwardedRef,
setLocalRef,
}: Args): (ref: ElementRef<any>) => void {
return function forwardRef(ref: ElementRef<any>) {
const forwardedRef = getForwardedRef();
setLocalRef(ref);
// Forward to user ref prop (if one has been specified)
if (typeof forwardedRef === 'function') {
// Handle function-based refs. String-based refs are handled as functions.
forwardedRef(ref);
} else if (typeof forwardedRef === 'object' && forwardedRef != null) {
// Handle createRef-based refs
forwardedRef.current = ref;
}
};
}
module.exports = setAndForwardRef;