diff --git a/packages/runtime/__tests__/ImplWrapper/ImplWrapper.spec.tsx b/packages/runtime/__tests__/ImplWrapper/ImplWrapper.spec.tsx
index bf38700f..2add3789 100644
--- a/packages/runtime/__tests__/ImplWrapper/ImplWrapper.spec.tsx
+++ b/packages/runtime/__tests__/ImplWrapper/ImplWrapper.spec.tsx
@@ -1,6 +1,7 @@
import '@testing-library/jest-dom/extend-expect';
import { render, screen, waitFor, act } from '@testing-library/react';
import produce from 'immer';
+import React from 'react';
import { initSunmaoUI } from '../../src';
import { TestLib } from '../testLib';
import { destroyTimesMap, renderTimesMap, clearTesterMap } from '../testLib/Tester';
@@ -11,6 +12,7 @@ import {
MergeStateSchema,
AsyncMergeStateSchema,
TabsWithSlotsSchema,
+ ParentRerenderSchema,
} from './mockSchema';
// A pure single sunmao component will render twice when it mount.
@@ -68,6 +70,28 @@ describe('hidden trait condition', () => {
});
});
+describe('when parent rerender change', () => {
+ it('the children should not rerender', () => {
+ const { App, stateManager, apiService } = initSunmaoUI({ libs: [TestLib] });
+ stateManager.noConsoleError = true;
+ const { unmount } = render();
+ const childTester = screen.getByTestId('tester');
+ expect(childTester).toHaveTextContent(SingleComponentRenderTimes);
+ act(() => {
+ apiService.send('uiMethod', {
+ componentId: 'input',
+ name: 'setValue',
+ parameters: 'foo',
+ });
+ });
+ expect(childTester).toHaveTextContent(SingleComponentRenderTimes);
+ expect(stateManager.store['input'].value).toBe('foo');
+
+ unmount();
+ clearTesterMap();
+ });
+});
+
describe('when component merge state synchronously', () => {
it('it will not cause extra render', () => {
const { App, stateManager } = initSunmaoUI({ libs: [TestLib] });
diff --git a/packages/runtime/__tests__/ImplWrapper/mockSchema.ts b/packages/runtime/__tests__/ImplWrapper/mockSchema.ts
index 47ba3644..442484c6 100644
--- a/packages/runtime/__tests__/ImplWrapper/mockSchema.ts
+++ b/packages/runtime/__tests__/ImplWrapper/mockSchema.ts
@@ -84,6 +84,55 @@ export const HiddenTraitSchema: Application = {
},
};
+export const ParentRerenderSchema: Application = {
+ version: 'sunmao/v1',
+ kind: 'Application',
+ metadata: {
+ name: 'some App',
+ },
+ spec: {
+ components: [
+ {
+ id: 'input',
+ type: 'test/v1/input',
+ properties: {
+ defaultValue: '',
+ },
+ traits: [],
+ },
+ {
+ id: 'stack6',
+ type: 'core/v1/stack',
+ properties: {
+ spacing: 12,
+ direction: 'horizontal',
+ align: 'auto',
+ wrap: '{{!!input.value}}',
+ justify: 'flex-start',
+ },
+ traits: [],
+ },
+ {
+ id: 'tester',
+ type: 'test/v1/tester',
+ properties: {},
+ traits: [
+ {
+ type: 'core/v1/slot',
+ properties: {
+ container: {
+ id: 'stack6',
+ slot: 'content',
+ },
+ ifCondition: true,
+ },
+ },
+ ],
+ },
+ ],
+ },
+};
+
export const MergeStateSchema: Application = {
version: 'sunmao/v1',
kind: 'Application',
diff --git a/packages/runtime/src/components/_internal/ImplWrapper/ImplWrapper.tsx b/packages/runtime/src/components/_internal/ImplWrapper/ImplWrapper.tsx
index 7f2f7921..c667502a 100644
--- a/packages/runtime/src/components/_internal/ImplWrapper/ImplWrapper.tsx
+++ b/packages/runtime/src/components/_internal/ImplWrapper/ImplWrapper.tsx
@@ -2,6 +2,7 @@ import React from 'react';
import { ImplWrapperProps } from '../../../types';
import { shallowCompare } from '@sunmao-ui/shared';
import { UnmountImplWrapper } from './UnmountImplWrapper';
+import { isEqual } from 'lodash';
export const ImplWrapper = React.memo(
UnmountImplWrapper,
@@ -10,20 +11,19 @@ export const ImplWrapper = React.memo(
const nextChildren = nextProps.childrenMap[nextProps.component.id]?._grandChildren;
const prevComponent = prevProps.component;
const nextComponent = nextProps.component;
- let isEqual = false;
+ let isComponentEqual = false;
if (prevChildren && nextChildren) {
- isEqual = shallowCompare(prevChildren, nextChildren);
+ isComponentEqual = shallowCompare(prevChildren, nextChildren);
} else if (prevChildren === nextChildren) {
- isEqual = true;
+ isComponentEqual = true;
}
-
return (
- isEqual &&
+ isComponentEqual &&
prevComponent === nextComponent &&
// TODO: keep ImplWrapper memorized and get slot props from store
shallowCompare(prevProps.slotProps, nextProps.slotProps) &&
- shallowCompare(prevProps.slotContext, nextProps.slotContext)
+ isEqual(prevProps.slotContext, nextProps.slotContext)
);
}
);