diff --git a/.changeset/fair-islands-think.md b/.changeset/fair-islands-think.md new file mode 100644 index 00000000000..e0a9d489424 --- /dev/null +++ b/.changeset/fair-islands-think.md @@ -0,0 +1,5 @@ +--- +"@builder.io/sdk-react-native": patch +--- + +Added deep memo comparison using react-fast-compare. diff --git a/packages/sdks-tests/src/e2e-tests/large-reactive-state.spec.ts b/packages/sdks-tests/src/e2e-tests/large-reactive-state.spec.ts index 6e5d4da2e6c..08262b1bfc4 100644 --- a/packages/sdks-tests/src/e2e-tests/large-reactive-state.spec.ts +++ b/packages/sdks-tests/src/e2e-tests/large-reactive-state.spec.ts @@ -38,6 +38,9 @@ test.describe('Large Reactive State', () => { // Initial state await expect(page.getByText('0', { exact: true })).toBeVisible(); + // log page contents + console.log(await page.content()); + // Increment multiple times for (let i = 1; i <= 5; i++) { await page.getByText('Increment Number').click(); diff --git a/packages/sdks/mitosis.config.cjs b/packages/sdks/mitosis.config.cjs index 3a7c72e3d34..abbd9591bf6 100644 --- a/packages/sdks/mitosis.config.cjs +++ b/packages/sdks/mitosis.config.cjs @@ -174,13 +174,20 @@ const MEMOIZING_BLOCKS_COMPONENT_PLUGIN = () => ({ imports: { memo: 'memo' }, path: 'react', }); + json.imports.push({ + imports: { isEqual: 'default' }, + path: 'react-fast-compare', + }); } if (json.name === 'Blocks') { json.imports.push({ imports: { memo: 'memo' }, path: 'react', }); - + json.imports.push({ + imports: { isEqual: 'default' }, + path: 'react-fast-compare', + }); json.hooks.init = { code: ` ${json.hooks.init?.code || ''} @@ -224,6 +231,7 @@ const MEMOIZING_BLOCKS_COMPONENT_PLUGIN = () => ({ data: { code: 'props.blocks', type: 'single' }, renderItem: { code: 'renderItem', type: 'single' }, keyExtractor: { code: 'keyExtractor', type: 'single' }, + extraData: { code: 'builderContext', type: 'single' }, removeClippedSubviews: { code: 'true', type: 'single' }, maxToRenderPerBatch: { code: '10', type: 'single' }, windowSize: { code: '5', type: 'single' }, @@ -240,13 +248,13 @@ const MEMOIZING_BLOCKS_COMPONENT_PLUGIN = () => ({ if (json.name === 'Blocks') { return code.replace( 'export default Blocks', - 'export default memo(Blocks)' + 'export default memo(Blocks, isEqual)' ); } if (json.name === 'Block') { return code.replace( 'export default Block', - 'export default memo(Block)' + 'export default memo(Block, isEqual)' ); } return code; diff --git a/packages/sdks/output/react-native/package.json b/packages/sdks/output/react-native/package.json index 3ec2ede9afb..cda7dff7ab3 100644 --- a/packages/sdks/output/react-native/package.json +++ b/packages/sdks/output/react-native/package.json @@ -111,6 +111,7 @@ "@react-native-async-storage/async-storage": "1.23.1", "css-to-react-native": "^3.2.0", "isolated-vm": "^6.0.0", + "react-fast-compare": "^3.2.2", "react-native-storage": "^1.0.1", "react-native-video": "^5.1.1" }, diff --git a/packages/sdks/src/functions/evaluate/helpers.ts b/packages/sdks/src/functions/evaluate/helpers.ts index 3b3932a6878..7c68c671426 100644 --- a/packages/sdks/src/functions/evaluate/helpers.ts +++ b/packages/sdks/src/functions/evaluate/helpers.ts @@ -133,7 +133,7 @@ export function flattenState({ rootSetState: rootSetState ? (subState) => { target[prop] = subState; - rootSetState(target); + rootSetState({ ...target }); } : undefined, }); @@ -149,8 +149,8 @@ export function flattenState({ } target[prop] = value; - - rootSetState?.(target); + // Pass a new object reference so React/RN detects the state change + rootSetState?.({ ...target }); return true; }, }); diff --git a/yarn.lock b/yarn.lock index d8ee6e98da0..8ca5d8c1a83 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7093,6 +7093,7 @@ __metadata: babel-plugin-module-resolver: ^5.0.0 css-to-react-native: ^3.2.0 isolated-vm: ^6.0.0 + react-fast-compare: ^3.2.2 react-native-builder-bob: ^0.21.3 react-native-storage: ^1.0.1 react-native-url-polyfill: ^2.0.0