From b14d7fa4b88dad5f0017d084e462952c700aa2ad Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Fri, 9 Dec 2022 14:43:52 +0000 Subject: [PATCH] Add support for setNativeProps to Fabric (#25737) Add support for `setNativeProps` in Fabric to make migration to the new architecture easier. The React Native part of this has already landed in the core and iOS in https://github.com/facebook/react-native/commit/1d3fa40c59b234f21f516db85c322ec0ed0311e0. It is still recommended to move away from `setNativeProps` because the API will not work with future features. --- .../src/ReactFabricHostConfig.js | 16 +++++++++++----- .../InitializeNativeFabricUIManager.js | 2 ++ .../ReactFabricHostComponent-test.internal.js | 14 ++++---------- scripts/flow/react-native-host-hooks.js | 2 +- 4 files changed, 18 insertions(+), 16 deletions(-) diff --git a/packages/react-native-renderer/src/ReactFabricHostConfig.js b/packages/react-native-renderer/src/ReactFabricHostConfig.js index 078bf1f11ac6f..b6d370882ae4e 100644 --- a/packages/react-native-renderer/src/ReactFabricHostConfig.js +++ b/packages/react-native-renderer/src/ReactFabricHostConfig.js @@ -18,7 +18,10 @@ import type { TouchedViewDataAtPoint, } from './ReactNativeTypes'; -import {mountSafeCallback_NOT_REALLY_SAFE} from './NativeMethodsMixinUtils'; +import { + mountSafeCallback_NOT_REALLY_SAFE, + warnForStyleProps, +} from './NativeMethodsMixinUtils'; import {create, diff} from './ReactNativeAttributePayload'; import {dispatchEvent} from './ReactFabricEventEmitter'; @@ -52,6 +55,7 @@ const { unstable_DefaultEventPriority: FabricDefaultPriority, unstable_DiscreteEventPriority: FabricDiscretePriority, unstable_getCurrentEventPriority: fabricGetCurrentEventPriority, + setNativeProps, } = nativeFabricUIManager; const {get: getViewConfigForType} = ReactNativeViewConfigRegistry; @@ -208,12 +212,14 @@ class ReactFabricHostComponent { setNativeProps(nativeProps: Object) { if (__DEV__) { - console.error( - 'Warning: setNativeProps is not currently supported in Fabric', - ); + warnForStyleProps(nativeProps, this.viewConfig.validAttributes); } + const updatePayload = create(nativeProps, this.viewConfig.validAttributes); - return; + const {stateNode} = this._internalInstanceHandle; + if (stateNode != null && updatePayload != null) { + setNativeProps(stateNode.node, updatePayload); + } } // This API (addEventListener, removeEventListener) attempts to adhere to the diff --git a/packages/react-native-renderer/src/__mocks__/react-native/Libraries/ReactPrivate/InitializeNativeFabricUIManager.js b/packages/react-native-renderer/src/__mocks__/react-native/Libraries/ReactPrivate/InitializeNativeFabricUIManager.js index abb2883d387ec..ab4fc291d6d6e 100644 --- a/packages/react-native-renderer/src/__mocks__/react-native/Libraries/ReactPrivate/InitializeNativeFabricUIManager.js +++ b/packages/react-native-renderer/src/__mocks__/react-native/Libraries/ReactPrivate/InitializeNativeFabricUIManager.js @@ -117,6 +117,8 @@ const RCTFabricUIManager = { dispatchCommand: jest.fn(), + setNativeProps: jest.fn(), + sendAccessibilityEvent: jest.fn(), registerEventHandler: jest.fn(function registerEventHandler(callback) {}), diff --git a/packages/react-native-renderer/src/__tests__/ReactFabricHostComponent-test.internal.js b/packages/react-native-renderer/src/__tests__/ReactFabricHostComponent-test.internal.js index 337a4976bbe82..51e056d1c8bce 100644 --- a/packages/react-native-renderer/src/__tests__/ReactFabricHostComponent-test.internal.js +++ b/packages/react-native-renderer/src/__tests__/ReactFabricHostComponent-test.internal.js @@ -38,7 +38,7 @@ function mockRenderKeys(keyLists) { const mockContainerTag = 11; const MockView = createReactNativeComponentClass('RCTMockView', () => ({ - validAttributes: {}, + validAttributes: {foo: true}, uiViewClassName: 'RCTMockView', })); @@ -200,21 +200,15 @@ describe('measureLayout', () => { }); describe('setNativeProps', () => { - test('setNativeProps(...) emits a warning', () => { + test('setNativeProps(...) invokes setNativeProps on Fabric UIManager', () => { const { UIManager, } = require('react-native/Libraries/ReactPrivate/ReactNativePrivateInterface'); const [[fooRef]] = mockRenderKeys([['foo']]); + fooRef.setNativeProps({foo: 'baz'}); - expect(() => { - fooRef.setNativeProps({}); - }).toErrorDev( - ['Warning: setNativeProps is not currently supported in Fabric'], - { - withoutStack: true, - }, - ); expect(UIManager.updateView).not.toBeCalled(); + expect(nativeFabricUIManager.setNativeProps).toHaveBeenCalledTimes(1); }); }); diff --git a/scripts/flow/react-native-host-hooks.js b/scripts/flow/react-native-host-hooks.js index 584f24ee084c1..e3c98114935fc 100644 --- a/scripts/flow/react-native-host-hooks.js +++ b/scripts/flow/react-native-host-hooks.js @@ -186,7 +186,7 @@ declare var nativeFabricUIManager: { payload: Object, ) => void, ) => void, - + setNativeProps: (node: Object, nativeProps: Object) => Object, dispatchCommand: (node: Object, command: string, args: Array) => void, sendAccessibilityEvent: (node: Object, eventTypeName: string) => void,