Skip to content

Commit 5578c14

Browse files
committed
perf: useModal #6517
1 parent 69640c0 commit 5578c14

File tree

6 files changed

+71
-67
lines changed

6 files changed

+71
-67
lines changed

.jest.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ module.exports = {
3131
testRegex: getTestRegex(libDir),
3232
moduleNameMapper: {
3333
'^@/(.*)$/': '<rootDir>/$1',
34-
'ant-design-vue$/': '<rootDir>/components/index.ts',
35-
'ant-design-vue/es/': '<rootDir>/components',
34+
'^ant-design-vue$': '<rootDir>/components/index',
35+
'^ant-design-vue/es/(.*)$': '<rootDir>/components/$1',
3636
},
3737
snapshotSerializers: ['<rootDir>/node_modules/jest-serializer-vue'],
3838
collectCoverage: process.env.COVERAGE === 'true',

components/modal/__tests__/__snapshots__/demo.test.js.snap

+23-12
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,5 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3-
exports[`renders ./components/modal/demo/HookModal.vue correctly 1`] = `
4-
<div><button class="ant-btn ant-btn-default" type="button">
5-
<!----><span>Confirm</span>
6-
</button><button class="ant-btn ant-btn-default" type="button">
7-
<!----><span>With promise</span>
8-
</button><button class="ant-btn ant-btn-dashed" type="button">
9-
<!----><span>Delete</span>
10-
</button><button class="ant-btn ant-btn-dashed" type="button">
11-
<!----><span>With extra props</span>
12-
</button></div>
13-
`;
14-
153
exports[`renders ./components/modal/demo/async.vue correctly 1`] = `
164
<div><button class="ant-btn ant-btn-primary" type="button">
175
<!----><span>Open Modal with async logic</span>
@@ -85,6 +73,29 @@ exports[`renders ./components/modal/demo/fullscreen.vue correctly 1`] = `
8573
</div>
8674
`;
8775

76+
exports[`renders ./components/modal/demo/hook-modal.vue correctly 1`] = `
77+
<div class="ant-space ant-space-horizontal ant-space-align-center" style="flex-wrap: wrap; margin-bottom: -8px;">
78+
<div class="ant-space-item" style="margin-right: 8px; padding-bottom: 8px;"><button class="ant-btn ant-btn-default" type="button">
79+
<!----><span>Confirm</span>
80+
</button></div>
81+
<!---->
82+
<div class="ant-space-item" style="margin-right: 8px; padding-bottom: 8px;"><button class="ant-btn ant-btn-default" type="button">
83+
<!----><span>With promise</span>
84+
</button></div>
85+
<!---->
86+
<div class="ant-space-item" style="margin-right: 8px; padding-bottom: 8px;"><button class="ant-btn ant-btn-dashed" type="button">
87+
<!----><span>Delete</span>
88+
</button></div>
89+
<!---->
90+
<div class="ant-space-item" style="margin-right: 8px; padding-bottom: 8px;"><button class="ant-btn ant-btn-dashed" type="button">
91+
<!----><span>With extra props</span>
92+
</button></div>
93+
<!---->
94+
<div class="ant-space-item" style="padding-bottom: 8px;"></div>
95+
<!---->
96+
</div>
97+
`;
98+
8899
exports[`renders ./components/modal/demo/info.vue correctly 1`] = `
89100
<div class="ant-space ant-space-horizontal ant-space-align-center" style="flex-wrap: wrap; margin-bottom: -8px;">
90101
<div class="ant-space-item" style="margin-right: 8px; padding-bottom: 8px;"><button class="ant-btn ant-btn-default" type="button">

components/modal/__tests__/confirm.test.js

+12-20
Original file line numberDiff line numberDiff line change
@@ -98,25 +98,17 @@ describe('Modal.confirm triggers callbacks correctly', () => {
9898
});
9999

100100
it('trigger onCancel once when click on cancel button', async () => {
101-
const arr = ['info'];
102-
for (let type of arr) {
103-
Modal[type]({
104-
title: 'title',
105-
content: 'content',
106-
});
107-
await sleep();
108-
expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(1);
109-
// $$('.ant-btn')[0].click();
110-
// await sleep(2000);
111-
// expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(0);
112-
}
101+
const onCancel = jest.fn();
102+
const onOk = jest.fn();
103+
await open({
104+
title: 'title',
105+
content: 'content',
106+
onCancel,
107+
onOk,
108+
});
109+
await sleep();
110+
$$('.ant-btn')[0].click();
111+
expect(onCancel.mock.calls.length).toBe(1);
112+
expect(onOk.mock.calls.length).toBe(0);
113113
});
114-
115-
// it('should render title', async () => {
116-
// open({
117-
// title: () => <span>title</span>,
118-
// });
119-
// await sleep();
120-
// expect($$('.ant-modal-confirm-title')[0].innerHTML).toBe('<span>title</span>');
121-
// });
122114
});

components/modal/demo/HookModal.vue renamed to components/modal/demo/hook-modal.vue

+8-8
Original file line numberDiff line numberDiff line change
@@ -17,25 +17,25 @@ Use `Modal.useModal` to get `contextHolder` with context accessible issue.
1717
</docs>
1818

1919
<template>
20-
<div>
20+
<a-space wrap>
2121
<a-button @click="showConfirm">Confirm</a-button>
2222
<a-button @click="showPromiseConfirm">With promise</a-button>
2323
<a-button type="dashed" @click="showDeleteConfirm">Delete</a-button>
2424
<a-button type="dashed" @click="showPropsConfirm">With extra props</a-button>
2525
<contextHolder />
26-
</div>
26+
</a-space>
2727
</template>
2828

2929
<script lang="ts" setup>
3030
import { Modal } from 'ant-design-vue';
3131
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
32-
import { createVNode } from 'vue';
32+
import { h } from 'vue';
3333
const [modal, contextHolder] = Modal.useModal();
3434
const showConfirm = () => {
3535
modal.confirm({
3636
title: 'Do you Want to delete these items?',
37-
icon: createVNode(ExclamationCircleOutlined),
38-
content: createVNode('div', { style: 'color:red;' }, 'Some descriptions'),
37+
icon: h(ExclamationCircleOutlined),
38+
content: h('div', { style: 'color:red;' }, 'Some descriptions'),
3939
onOk() {
4040
console.log('OK');
4141
},
@@ -48,7 +48,7 @@ const showConfirm = () => {
4848
const showDeleteConfirm = () => {
4949
modal.confirm({
5050
title: 'Are you sure delete this task?',
51-
icon: createVNode(ExclamationCircleOutlined),
51+
icon: h(ExclamationCircleOutlined),
5252
content: 'Some descriptions',
5353
okText: 'Yes',
5454
okType: 'danger',
@@ -64,7 +64,7 @@ const showDeleteConfirm = () => {
6464
const showPropsConfirm = () => {
6565
modal.confirm({
6666
title: 'Are you sure delete this task?',
67-
icon: createVNode(ExclamationCircleOutlined),
67+
icon: h(ExclamationCircleOutlined),
6868
content: 'Some descriptions',
6969
okText: 'Yes',
7070
okType: 'danger',
@@ -84,7 +84,7 @@ const showPropsConfirm = () => {
8484
function showPromiseConfirm() {
8585
modal.confirm({
8686
title: 'Do you want to delete these items?',
87-
icon: createVNode(ExclamationCircleOutlined),
87+
icon: h(ExclamationCircleOutlined),
8888
content: 'When clicked the OK button, this dialog will be closed after 1 second',
8989
async onOk() {
9090
try {

components/modal/demo/index.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import Width from './width.vue';
3232
import Fullscreen from './fullscreen.vue';
3333
import ButtonProps from './button-props.vue';
3434
import modalRenderVue from './modal-render.vue';
35-
import HookModal from './HookModal.vue';
35+
import HookModal from './hook-modal.vue';
3636
import CN from '../index.zh-CN.md';
3737
import US from '../index.en-US.md';
3838
import { defineComponent } from 'vue';

components/modal/useModal/index.tsx

+25-24
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import type { ComputedRef, Ref } from 'vue';
2-
import { isRef, unref, computed, defineComponent, ref, watch } from 'vue';
3-
import type { VueNode } from '../../_util/type';
1+
import type { Ref } from 'vue';
2+
import { isRef, unref, computed, defineComponent, shallowRef, watch } from 'vue';
3+
import type { MaybeRef, VueNode } from '../../_util/type';
44
import type { ModalFuncProps } from '../Modal';
55
import type { HookModalRef } from './HookModal';
66
import type { ModalStaticFunctions } from '../confirm';
@@ -12,28 +12,29 @@ import destroyFns from '../destroyFns';
1212
let uuid = 0;
1313

1414
interface ElementsHolderRef {
15-
addModal: (modal: ComputedRef<JSX.Element>) => () => void;
15+
addModal: (modal: () => JSX.Element) => () => void;
1616
}
1717

1818
const ElementsHolder = defineComponent({
1919
name: 'ElementsHolder',
2020
inheritAttrs: false,
2121
setup(_, { expose }) {
22-
const modals = ref<ComputedRef<JSX.Element>[]>([]);
23-
const addModal = (modal: ComputedRef<JSX.Element>) => {
22+
const modals = shallowRef<(() => JSX.Element)[]>([]);
23+
const addModal = (modal: () => JSX.Element) => {
2424
modals.value.push(modal);
25+
modals.value = modals.value.slice();
2526
return () => {
2627
modals.value = modals.value.filter(currentModal => currentModal !== modal);
2728
};
2829
};
2930

3031
expose({ addModal });
3132
return () => {
32-
return <>{modals.value.map(modal => modal.value)}</>;
33+
return modals.value.map(modal => modal());
3334
};
3435
},
3536
});
36-
export type ModalFuncWithRef = (props: Ref<ModalFuncProps> | ModalFuncProps) => {
37+
export type ModalFuncWithRef = (props: MaybeRef<ModalFuncProps>) => {
3738
destroy: () => void;
3839
update: (configUpdate: ModalFuncProps) => void;
3940
};
@@ -42,9 +43,9 @@ function useModal(): readonly [
4243
Omit<ModalStaticFunctions<ModalFuncWithRef>, 'warn'>,
4344
() => VueNode,
4445
] {
45-
const holderRef = ref<ElementsHolderRef>(null);
46+
const holderRef = shallowRef<ElementsHolderRef>(null);
4647
// ========================== Effect ==========================
47-
const actionQueue = ref([]);
48+
const actionQueue = shallowRef([]);
4849
watch(
4950
actionQueue,
5051
() => {
@@ -65,10 +66,10 @@ function useModal(): readonly [
6566
const getConfirmFunc = (withFunc: (config: ModalFuncProps) => ModalFuncProps) =>
6667
function hookConfirm(config: Ref<ModalFuncProps> | ModalFuncProps) {
6768
uuid += 1;
68-
const open = ref(true);
69-
const modalRef = ref<HookModalRef>(null);
70-
const configRef = ref(unref(config));
71-
const updateConfig = ref({});
69+
const open = shallowRef(true);
70+
const modalRef = shallowRef<HookModalRef>(null);
71+
const configRef = shallowRef(unref(config));
72+
const updateConfig = shallowRef({});
7273
watch(
7374
() => config,
7475
val => {
@@ -78,9 +79,17 @@ function useModal(): readonly [
7879
});
7980
},
8081
);
82+
83+
const destroyAction = (...args: any[]) => {
84+
open.value = false;
85+
const triggerCancel = args.some(param => param && param.triggerCancel);
86+
if (configRef.value.onCancel && triggerCancel) {
87+
configRef.value.onCancel(() => {}, ...args.slice(1));
88+
}
89+
};
8190
// eslint-disable-next-line prefer-const
8291
let closeFunc: Function | undefined;
83-
const modal = computed(() => (
92+
const modal = () => (
8493
<HookModal
8594
key={`modal-${uuid}`}
8695
config={withFunc(configRef.value)}
@@ -91,22 +100,14 @@ function useModal(): readonly [
91100
closeFunc?.();
92101
}}
93102
/>
94-
));
103+
);
95104

96105
closeFunc = holderRef.value?.addModal(modal);
97106

98107
if (closeFunc) {
99108
destroyFns.push(closeFunc);
100109
}
101110

102-
const destroyAction = (...args: any[]) => {
103-
open.value = false;
104-
const triggerCancel = args.some(param => param && param.triggerCancel);
105-
if (configRef.value.onCancel && triggerCancel) {
106-
configRef.value.onCancel(() => {}, ...args.slice(1));
107-
}
108-
};
109-
110111
const updateAction = (newConfig: ModalFuncProps) => {
111112
configRef.value = {
112113
...configRef.value,

0 commit comments

Comments
 (0)