@samitouri / QOS-React-2 / commits / 515746c217

Add findHostInstance_deprecated to the React Native Renderer (#17224)

Eli White committed Oct 30, 2019 at 11:42 UTC 515746c217ef97a1a5745f15bf9f1cae3c84d2c6
5 files changed +294 -2
packages/react-native-renderer/src/ReactFabric.js
+52 -1
@@ -7,7 +7,7 @@
7 * @flow
8 */
9
10 -import type {ReactFabricType} from './ReactNativeTypes';
10 +import type {ReactFabricType, HostComponent} from './ReactNativeTypes';
11 import type {ReactNodeList} from 'shared/ReactTypes';
12
13 import './ReactFabricInjection';
@@ -44,6 +44,54 @@ import warningWithoutStack from 'shared/warningWithoutStack';
44
45 const ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner;
46
47 +function findHostInstance_deprecated(
48 + componentOrHandle: any,
49 +): ?HostComponent<mixed> {
50 + if (__DEV__) {
51 + const owner = ReactCurrentOwner.current;
52 + if (owner !== null && owner.stateNode !== null) {
53 + warningWithoutStack(
54 + owner.stateNode._warnedAboutRefsInRender,
55 + '%s is accessing findNodeHandle inside its render(). ' +
56 + 'render() should be a pure function of props and state. It should ' +
57 + 'never access something that requires stale data from the previous ' +
58 + 'render, such as refs. Move this logic to componentDidMount and ' +
59 + 'componentDidUpdate instead.',
60 + getComponentName(owner.type) || 'A component',
61 + );
62 +
63 + owner.stateNode._warnedAboutRefsInRender = true;
64 + }
65 + }
66 + if (componentOrHandle == null) {
67 + return null;
68 + }
69 + if (componentOrHandle._nativeTag) {
70 + return componentOrHandle;
71 + }
72 + if (componentOrHandle.canonical && componentOrHandle.canonical._nativeTag) {
73 + return componentOrHandle.canonical;
74 + }
75 + let hostInstance;
76 + if (__DEV__) {
77 + hostInstance = findHostInstanceWithWarning(
78 + componentOrHandle,
79 + 'findHostInstance_deprecated',
80 + );
81 + } else {
82 + hostInstance = findHostInstance(componentOrHandle);
83 + }
84 +
85 + if (hostInstance == null) {
86 + return hostInstance;
87 + }
88 + if ((hostInstance: any).canonical) {
89 + // Fabric
90 + return (hostInstance: any).canonical;
91 + }
92 + return hostInstance;
93 +}
94 +
95 function findNodeHandle(componentOrHandle: any): ?number {
96 if (__DEV__) {
97 const owner = ReactCurrentOwner.current;
@@ -108,6 +156,9 @@ const roots = new Map();
156 const ReactFabric: ReactFabricType = {
157 NativeComponent: ReactNativeComponent(findNodeHandle, findHostInstance),
158
159 + // This is needed for implementation details of TouchableNativeFeedback
160 + // Remove this once TouchableNativeFeedback doesn't use cloneElement
161 + findHostInstance_deprecated,
162 findNodeHandle,
163
164 dispatchCommand(handle: any, command: string, args: Array<any>) {
packages/react-native-renderer/src/ReactNativeRenderer.js
+52 -1
@@ -7,7 +7,7 @@
7 * @flow
8 */
9
10 -import type {ReactNativeType} from './ReactNativeTypes';
10 +import type {ReactNativeType, HostComponent} from './ReactNativeTypes';
11 import type {ReactNodeList} from 'shared/ReactTypes';
12
13 import './ReactNativeInjection';
@@ -47,6 +47,54 @@ import warningWithoutStack from 'shared/warningWithoutStack';
47
48 const ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner;
49
50 +function findHostInstance_deprecated(
51 + componentOrHandle: any,
52 +): ?HostComponent<mixed> {
53 + if (__DEV__) {
54 + const owner = ReactCurrentOwner.current;
55 + if (owner !== null && owner.stateNode !== null) {
56 + warningWithoutStack(
57 + owner.stateNode._warnedAboutRefsInRender,
58 + '%s is accessing findNodeHandle inside its render(). ' +
59 + 'render() should be a pure function of props and state. It should ' +
60 + 'never access something that requires stale data from the previous ' +
61 + 'render, such as refs. Move this logic to componentDidMount and ' +
62 + 'componentDidUpdate instead.',
63 + getComponentName(owner.type) || 'A component',
64 + );
65 +
66 + owner.stateNode._warnedAboutRefsInRender = true;
67 + }
68 + }
69 + if (componentOrHandle == null) {
70 + return null;
71 + }
72 + if (componentOrHandle._nativeTag) {
73 + return componentOrHandle;
74 + }
75 + if (componentOrHandle.canonical && componentOrHandle.canonical._nativeTag) {
76 + return componentOrHandle.canonical;
77 + }
78 + let hostInstance;
79 + if (__DEV__) {
80 + hostInstance = findHostInstanceWithWarning(
81 + componentOrHandle,
82 + 'findHostInstance_deprecated',
83 + );
84 + } else {
85 + hostInstance = findHostInstance(componentOrHandle);
86 + }
87 +
88 + if (hostInstance == null) {
89 + return hostInstance;
90 + }
91 + if ((hostInstance: any).canonical) {
92 + // Fabric
93 + return (hostInstance: any).canonical;
94 + }
95 + return hostInstance;
96 +}
97 +
98 function findNodeHandle(componentOrHandle: any): ?number {
99 if (__DEV__) {
100 const owner = ReactCurrentOwner.current;
@@ -117,6 +165,9 @@ const roots = new Map();
165 const ReactNativeRenderer: ReactNativeType = {
166 NativeComponent: ReactNativeComponent(findNodeHandle, findHostInstance),
167
168 + // This is needed for implementation details of TouchableNativeFeedback
169 + // Remove this once TouchableNativeFeedback doesn't use cloneElement
170 + findHostInstance_deprecated,
171 findNodeHandle,
172
173 dispatchCommand(handle: any, command: string, args: Array<any>) {
packages/react-native-renderer/src/__tests__/ReactFabric-test.internal.js
+75
@@ -779,6 +779,81 @@ describe('ReactFabric', () => {
779 expect(touchStart2).toBeCalled();
780 });
781
782 + it('findHostInstance_deprecated should warn if used to find a host component inside StrictMode', () => {
783 + const View = createReactNativeComponentClass('RCTView', () => ({
784 + validAttributes: {foo: true},
785 + uiViewClassName: 'RCTView',
786 + }));
787 +
788 + let parent = undefined;
789 + let child = undefined;
790 +
791 + class ContainsStrictModeChild extends React.Component {
792 + render() {
793 + return (
794 + <StrictMode>
795 + <View ref={n => (child = n)} />
796 + </StrictMode>
797 + );
798 + }
799 + }
800 +
801 + ReactFabric.render(<ContainsStrictModeChild ref={n => (parent = n)} />, 11);
802 +
803 + let match;
804 + expect(
805 + () => (match = ReactFabric.findHostInstance_deprecated(parent)),
806 + ).toWarnDev([
807 + 'Warning: findHostInstance_deprecated is deprecated in StrictMode. ' +
808 + 'findHostInstance_deprecated was passed an instance of ContainsStrictModeChild which renders StrictMode children. ' +
809 + 'Instead, add a ref directly to the element you want to reference. ' +
810 + 'Learn more about using refs safely here: ' +
811 + 'https://fb.me/react-strict-mode-find-node' +
812 + '\n in RCTView (at **)' +
813 + '\n in StrictMode (at **)' +
814 + '\n in ContainsStrictModeChild (at **)',
815 + ]);
816 + expect(match).toBe(child);
817 + });
818 +
819 + it('findHostInstance_deprecated should warn if passed a component that is inside StrictMode', () => {
820 + const View = createReactNativeComponentClass('RCTView', () => ({
821 + validAttributes: {foo: true},
822 + uiViewClassName: 'RCTView',
823 + }));
824 +
825 + let parent = undefined;
826 + let child = undefined;
827 +
828 + class IsInStrictMode extends React.Component {
829 + render() {
830 + return <View ref={n => (child = n)} />;
831 + }
832 + }
833 +
834 + ReactFabric.render(
835 + <StrictMode>
836 + <IsInStrictMode ref={n => (parent = n)} />
837 + </StrictMode>,
838 + 11,
839 + );
840 +
841 + let match;
842 + expect(
843 + () => (match = ReactFabric.findHostInstance_deprecated(parent)),
844 + ).toWarnDev([
845 + 'Warning: findHostInstance_deprecated is deprecated in StrictMode. ' +
846 + 'findHostInstance_deprecated was passed an instance of IsInStrictMode which is inside StrictMode. ' +
847 + 'Instead, add a ref directly to the element you want to reference. ' +
848 + 'Learn more about using refs safely here: ' +
849 + 'https://fb.me/react-strict-mode-find-node' +
850 + '\n in RCTView (at **)' +
851 + '\n in IsInStrictMode (at **)' +
852 + '\n in StrictMode (at **)',
853 + ]);
854 + expect(match).toBe(child);
855 + });
856 +
857 it('findNodeHandle should warn if used to find a host component inside StrictMode', () => {
858 const View = createReactNativeComponentClass('RCTView', () => ({
859 validAttributes: {foo: true},
packages/react-native-renderer/src/__tests__/ReactFabricAndNative-test.internal.js
+40
@@ -34,6 +34,26 @@ describe('created with ReactFabric called with ReactNative', () => {
34 .ReactNativeViewConfigRegistry.register;
35 });
36
37 + it('find Fabric instances with the RN renderer', () => {
38 + const View = createReactNativeComponentClass('RCTView', () => ({
39 + validAttributes: {title: true},
40 + uiViewClassName: 'RCTView',
41 + }));
42 +
43 + let ref = React.createRef();
44 +
45 + class Component extends React.Component {
46 + render() {
47 + return <View title="foo" />;
48 + }
49 + }
50 +
51 + ReactFabric.render(<Component ref={ref} />, 11);
52 +
53 + let instance = ReactNative.findHostInstance_deprecated(ref.current);
54 + expect(instance._nativeTag).toBe(2);
55 + });
56 +
57 it('find Fabric nodes with the RN renderer', () => {
58 const View = createReactNativeComponentClass('RCTView', () => ({
59 validAttributes: {title: true},
@@ -94,6 +114,26 @@ describe('created with ReactNative called with ReactFabric', () => {
114 .ReactNativeViewConfigRegistry.register;
115 });
116
117 + it('find Paper instances with the Fabric renderer', () => {
118 + const View = createReactNativeComponentClass('RCTView', () => ({
119 + validAttributes: {title: true},
120 + uiViewClassName: 'RCTView',
121 + }));
122 +
123 + let ref = React.createRef();
124 +
125 + class Component extends React.Component {
126 + render() {
127 + return <View title="foo" />;
128 + }
129 + }
130 +
131 + ReactNative.render(<Component ref={ref} />, 11);
132 +
133 + let instance = ReactFabric.findHostInstance_deprecated(ref.current);
134 + expect(instance._nativeTag).toBe(3);
135 + });
136 +
137 it('find Paper nodes with the Fabric renderer', () => {
138 const View = createReactNativeComponentClass('RCTView', () => ({
139 validAttributes: {title: true},
packages/react-native-renderer/src/__tests__/ReactNativeMount-test.internal.js
+75
@@ -541,6 +541,81 @@ describe('ReactNative', () => {
541 );
542 });
543
544 + it('findHostInstance_deprecated should warn if used to find a host component inside StrictMode', () => {
545 + const View = createReactNativeComponentClass('RCTView', () => ({
546 + validAttributes: {foo: true},
547 + uiViewClassName: 'RCTView',
548 + }));
549 +
550 + let parent = undefined;
551 + let child = undefined;
552 +
553 + class ContainsStrictModeChild extends React.Component {
554 + render() {
555 + return (
556 + <StrictMode>
557 + <View ref={n => (child = n)} />
558 + </StrictMode>
559 + );
560 + }
561 + }
562 +
563 + ReactNative.render(<ContainsStrictModeChild ref={n => (parent = n)} />, 11);
564 +
565 + let match;
566 + expect(
567 + () => (match = ReactNative.findHostInstance_deprecated(parent)),
568 + ).toWarnDev([
569 + 'Warning: findHostInstance_deprecated is deprecated in StrictMode. ' +
570 + 'findHostInstance_deprecated was passed an instance of ContainsStrictModeChild which renders StrictMode children. ' +
571 + 'Instead, add a ref directly to the element you want to reference. ' +
572 + 'Learn more about using refs safely here: ' +
573 + 'https://fb.me/react-strict-mode-find-node' +
574 + '\n in RCTView (at **)' +
575 + '\n in StrictMode (at **)' +
576 + '\n in ContainsStrictModeChild (at **)',
577 + ]);
578 + expect(match).toBe(child);
579 + });
580 +
581 + it('findHostInstance_deprecated should warn if passed a component that is inside StrictMode', () => {
582 + const View = createReactNativeComponentClass('RCTView', () => ({
583 + validAttributes: {foo: true},
584 + uiViewClassName: 'RCTView',
585 + }));
586 +
587 + let parent = undefined;
588 + let child = undefined;
589 +
590 + class IsInStrictMode extends React.Component {
591 + render() {
592 + return <View ref={n => (child = n)} />;
593 + }
594 + }
595 +
596 + ReactNative.render(
597 + <StrictMode>
598 + <IsInStrictMode ref={n => (parent = n)} />
599 + </StrictMode>,
600 + 11,
601 + );
602 +
603 + let match;
604 + expect(
605 + () => (match = ReactNative.findHostInstance_deprecated(parent)),
606 + ).toWarnDev([
607 + 'Warning: findHostInstance_deprecated is deprecated in StrictMode. ' +
608 + 'findHostInstance_deprecated was passed an instance of IsInStrictMode which is inside StrictMode. ' +
609 + 'Instead, add a ref directly to the element you want to reference. ' +
610 + 'Learn more about using refs safely here: ' +
611 + 'https://fb.me/react-strict-mode-find-node' +
612 + '\n in RCTView (at **)' +
613 + '\n in IsInStrictMode (at **)' +
614 + '\n in StrictMode (at **)',
615 + ]);
616 + expect(match).toBe(child);
617 + });
618 +
619 it('findNodeHandle should warn if used to find a host component inside StrictMode', () => {
620 const View = createReactNativeComponentClass('RCTView', () => ({
621 validAttributes: {foo: true},