From e7f26c88157fe4de34bf45fa4f688ed1b5d4b991 Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Thu, 24 Nov 2022 18:40:16 +0000 Subject: [PATCH 1/2] Add support for setNativeProps to Fabric --- .../src/ReactFabricHostConfig.js | 10 ++++------ .../ReactPrivate/InitializeNativeFabricUIManager.js | 2 ++ .../ReactFabricHostComponent-test.internal.js | 12 +++--------- scripts/flow/react-native-host-hooks.js | 2 +- 4 files changed, 10 insertions(+), 16 deletions(-) diff --git a/packages/react-native-renderer/src/ReactFabricHostConfig.js b/packages/react-native-renderer/src/ReactFabricHostConfig.js index 078bf1f11ac6f..5536f8f1950bb 100644 --- a/packages/react-native-renderer/src/ReactFabricHostConfig.js +++ b/packages/react-native-renderer/src/ReactFabricHostConfig.js @@ -52,6 +52,7 @@ const { unstable_DefaultEventPriority: FabricDefaultPriority, unstable_DiscreteEventPriority: FabricDiscretePriority, unstable_getCurrentEventPriority: fabricGetCurrentEventPriority, + setNativeProps, } = nativeFabricUIManager; const {get: getViewConfigForType} = ReactNativeViewConfigRegistry; @@ -207,13 +208,10 @@ class ReactFabricHostComponent { } setNativeProps(nativeProps: Object) { - if (__DEV__) { - console.error( - 'Warning: setNativeProps is not currently supported in Fabric', - ); + const {stateNode} = this._internalInstanceHandle; + if (stateNode != null) { + setNativeProps(stateNode.node, nativeProps); } - - return; } // 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..59d5d5f92a5d7 100644 --- a/packages/react-native-renderer/src/__tests__/ReactFabricHostComponent-test.internal.js +++ b/packages/react-native-renderer/src/__tests__/ReactFabricHostComponent-test.internal.js @@ -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({}); - 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, From 1df8cf7cd7cd22edb4518dc6b9ed0030751a9f90 Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Fri, 9 Dec 2022 14:32:36 +0000 Subject: [PATCH 2/2] Pass props through function to flatten them --- .../src/ReactFabricHostConfig.js | 14 +++++++++++--- .../ReactFabricHostComponent-test.internal.js | 4 ++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/react-native-renderer/src/ReactFabricHostConfig.js b/packages/react-native-renderer/src/ReactFabricHostConfig.js index 5536f8f1950bb..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'; @@ -208,9 +211,14 @@ class ReactFabricHostComponent { } setNativeProps(nativeProps: Object) { + if (__DEV__) { + warnForStyleProps(nativeProps, this.viewConfig.validAttributes); + } + const updatePayload = create(nativeProps, this.viewConfig.validAttributes); + const {stateNode} = this._internalInstanceHandle; - if (stateNode != null) { - setNativeProps(stateNode.node, nativeProps); + if (stateNode != null && updatePayload != null) { + setNativeProps(stateNode.node, updatePayload); } } 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 59d5d5f92a5d7..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', })); @@ -206,7 +206,7 @@ describe('setNativeProps', () => { } = require('react-native/Libraries/ReactPrivate/ReactNativePrivateInterface'); const [[fooRef]] = mockRenderKeys([['foo']]); - fooRef.setNativeProps({}); + fooRef.setNativeProps({foo: 'baz'}); expect(UIManager.updateView).not.toBeCalled(); expect(nativeFabricUIManager.setNativeProps).toHaveBeenCalledTimes(1);