diff --git a/packages/react-native-renderer/src/ReactNativeAttributePayloadFabric.js b/packages/react-native-renderer/src/ReactNativeAttributePayloadFabric.js index 8b8e45e7514f1..0d4388335a0c6 100644 --- a/packages/react-native-renderer/src/ReactNativeAttributePayloadFabric.js +++ b/packages/react-native-renderer/src/ReactNativeAttributePayloadFabric.js @@ -294,14 +294,17 @@ function diffProperties( prevProp = prevProps[propKey]; nextProp = nextProps[propKey]; - // functions are converted to booleans as markers that the associated - // events should be sent from native. if (typeof nextProp === 'function') { - nextProp = (true: any); - // If nextProp is not a function, then don't bother changing prevProp - // since nextProp will win and go into the updatePayload regardless. - if (typeof prevProp === 'function') { - prevProp = (true: any); + const attributeConfigHasProcess = typeof attributeConfig === 'object' && typeof attributeConfig.process === 'function'; + if (!attributeConfigHasProcess) { + // functions are converted to booleans as markers that the associated + // events should be sent from native. + nextProp = (true: any); + // If nextProp is not a function, then don't bother changing prevProp + // since nextProp will win and go into the updatePayload regardless. + if (typeof prevProp === 'function') { + prevProp = (true: any); + } } } @@ -485,18 +488,22 @@ function fastAddProperties( } else { continue; } - } else if (typeof prop === 'function') { - // A function prop. It represents an event handler. Pass it to native as 'true'. - newValue = true; - } else if (typeof attributeConfig !== 'object') { - // An atomic prop. Doesn't need to be flattened. - newValue = prop; - } else if (typeof attributeConfig.process === 'function') { - // An atomic prop with custom processing. - newValue = attributeConfig.process(prop); - } else if (typeof attributeConfig.diff === 'function') { - // An atomic prop with custom diffing. We don't need to do diffing when adding props. - newValue = prop; + } else if (typeof attributeConfig === 'object') { + if (typeof attributeConfig.process === 'function') { + // An atomic prop with custom processing. + newValue = attributeConfig.process(prop); + } else if (typeof attributeConfig.diff === 'function') { + // An atomic prop with custom diffing. We don't need to do diffing when adding props. + newValue = prop; + } + } else { + if (typeof prop === 'function') { + // A function prop. It represents an event handler. Pass it to native as 'true'. + newValue = true; + } else { + // An atomic prop. Doesn't need to be flattened. + newValue = prop; + } } if (newValue !== undefined) { diff --git a/packages/react-native-renderer/src/__tests__/ReactNativeAttributePayloadFabric-test.internal.js b/packages/react-native-renderer/src/__tests__/ReactNativeAttributePayloadFabric-test.internal.js index 9136c932e601e..573bb66999db8 100644 --- a/packages/react-native-renderer/src/__tests__/ReactNativeAttributePayloadFabric-test.internal.js +++ b/packages/react-native-renderer/src/__tests__/ReactNativeAttributePayloadFabric-test.internal.js @@ -102,6 +102,14 @@ describe('ReactNativeAttributePayloadFabric.create', () => { expect(processA).toBeCalledWith(2); }); + it('should use the process attribute for functions as well', () => { + const process = x => x; + const nextFunction = () => {}; + expect(create({a: nextFunction}, {a: {process}})).toEqual({ + a: nextFunction, + }); + }); + it('should work with undefined styles', () => { expect(create({style: undefined}, {style: {b: true}})).toEqual(null); expect(create({style: {a: '#ffffff', b: 1}}, {style: {b: true}})).toEqual({ @@ -455,4 +463,21 @@ describe('ReactNativeAttributePayloadFabric.diff', () => { ), ).toEqual(null); }); + + it('should use the process function config when prop is a function', () => { + const process = jest.fn(a => a); + const nextFunction = function () {}; + expect( + diff( + { + a: function () {}, + }, + { + a: nextFunction, + }, + {a: {process}}, + ), + ).toEqual({a: nextFunction}); + expect(process).toBeCalled(); + }); });