mirror of
https://github.com/ant-design/ant-design.git
synced 2024-12-01 23:29:30 +08:00
fix: Modal hooks update & destroy (#29584)
* fix: Modal update before render * test: Add test case * test: More test
This commit is contained in:
parent
e7938cad1c
commit
992b99c011
@ -1,5 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import CSSMotion from 'rc-motion';
|
import CSSMotion from 'rc-motion';
|
||||||
|
import { act } from 'react-dom/test-utils';
|
||||||
import { genCSSMotion } from 'rc-motion/lib/CSSMotion';
|
import { genCSSMotion } from 'rc-motion/lib/CSSMotion';
|
||||||
import { mount } from 'enzyme';
|
import { mount } from 'enzyme';
|
||||||
import Modal from '..';
|
import Modal from '..';
|
||||||
@ -48,15 +49,19 @@ describe('Modal.hook', () => {
|
|||||||
expect(wrapper.find('.ant-modal-body').length).toBeTruthy();
|
expect(wrapper.find('.ant-modal-body').length).toBeTruthy();
|
||||||
|
|
||||||
// Update instance
|
// Update instance
|
||||||
instance.update({
|
act(() => {
|
||||||
content: <div className="updated-content" />,
|
instance.update({
|
||||||
|
content: <div className="updated-content" />,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
expect(wrapper.find('.updated-content')).toHaveLength(1);
|
expect(wrapper.find('.updated-content')).toHaveLength(1);
|
||||||
|
|
||||||
// Destroy
|
// Destroy
|
||||||
instance.destroy();
|
act(() => {
|
||||||
jest.runAllTimers();
|
instance.destroy();
|
||||||
|
jest.runAllTimers();
|
||||||
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
expect(wrapper.find('Modal')).toHaveLength(0);
|
expect(wrapper.find('Modal')).toHaveLength(0);
|
||||||
|
|
||||||
@ -100,4 +105,62 @@ describe('Modal.hook', () => {
|
|||||||
wrapper.find('.ant-modal-wrap').simulate('click');
|
wrapper.find('.ant-modal-wrap').simulate('click');
|
||||||
expect(cancelCount).toEqual(2); // click modal wrapper, trigger onCancel
|
expect(cancelCount).toEqual(2); // click modal wrapper, trigger onCancel
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('update before render', () => {
|
||||||
|
const Demo = () => {
|
||||||
|
const [modal, contextHolder] = Modal.useModal();
|
||||||
|
|
||||||
|
const openBrokenModal = React.useCallback(() => {
|
||||||
|
const instance = modal.info({
|
||||||
|
title: 'Light',
|
||||||
|
});
|
||||||
|
|
||||||
|
instance.update({
|
||||||
|
title: 'Bamboo',
|
||||||
|
});
|
||||||
|
}, [modal]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="App">
|
||||||
|
{contextHolder}
|
||||||
|
<div className="open-hook-modal-btn" onClick={openBrokenModal}>
|
||||||
|
Test hook modal
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(<Demo />);
|
||||||
|
wrapper.find('.open-hook-modal-btn').simulate('click');
|
||||||
|
|
||||||
|
expect(wrapper.find('.ant-modal-confirm-title').text()).toEqual('Bamboo');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('destroy before render', () => {
|
||||||
|
const Demo = () => {
|
||||||
|
const [modal, contextHolder] = Modal.useModal();
|
||||||
|
|
||||||
|
const openBrokenModal = React.useCallback(() => {
|
||||||
|
const instance = modal.info({
|
||||||
|
title: 'Light',
|
||||||
|
});
|
||||||
|
|
||||||
|
instance.destroy();
|
||||||
|
}, [modal]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="App">
|
||||||
|
{contextHolder}
|
||||||
|
<div className="open-hook-modal-btn" onClick={openBrokenModal}>
|
||||||
|
Test hook modal
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(<Demo />);
|
||||||
|
wrapper.find('.open-hook-modal-btn').simulate('click');
|
||||||
|
|
||||||
|
expect(wrapper.exists('.ant-modal-confirm-title')).toBeFalsy();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -34,6 +34,21 @@ const ElementsHolder = React.memo(
|
|||||||
export default function useModal(): [Omit<ModalStaticFunctions, 'warn'>, React.ReactElement] {
|
export default function useModal(): [Omit<ModalStaticFunctions, 'warn'>, React.ReactElement] {
|
||||||
const holderRef = React.useRef<ElementsHolderRef>(null as any);
|
const holderRef = React.useRef<ElementsHolderRef>(null as any);
|
||||||
|
|
||||||
|
// ========================== Effect ==========================
|
||||||
|
const [actionQueue, setActionQueue] = React.useState<(() => void)[]>([]);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (actionQueue.length) {
|
||||||
|
const cloneQueue = [...actionQueue];
|
||||||
|
cloneQueue.forEach(action => {
|
||||||
|
action();
|
||||||
|
});
|
||||||
|
|
||||||
|
setActionQueue([]);
|
||||||
|
}
|
||||||
|
}, [actionQueue]);
|
||||||
|
|
||||||
|
// =========================== Hook ===========================
|
||||||
const getConfirmFunc = React.useCallback(
|
const getConfirmFunc = React.useCallback(
|
||||||
(withFunc: (config: ModalFuncProps) => ModalFuncProps) =>
|
(withFunc: (config: ModalFuncProps) => ModalFuncProps) =>
|
||||||
function hookConfirm(config: ModalFuncProps) {
|
function hookConfirm(config: ModalFuncProps) {
|
||||||
@ -57,13 +72,25 @@ export default function useModal(): [Omit<ModalStaticFunctions, 'warn'>, React.R
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
destroy: () => {
|
destroy: () => {
|
||||||
|
function destroyAction() {
|
||||||
|
modalRef.current?.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
if (modalRef.current) {
|
if (modalRef.current) {
|
||||||
modalRef.current.destroy();
|
destroyAction();
|
||||||
|
} else {
|
||||||
|
setActionQueue(prev => [...prev, destroyAction]);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
update: (newConfig: ModalFuncProps) => {
|
update: (newConfig: ModalFuncProps) => {
|
||||||
|
function updateAction() {
|
||||||
|
modalRef.current?.update(newConfig);
|
||||||
|
}
|
||||||
|
|
||||||
if (modalRef.current) {
|
if (modalRef.current) {
|
||||||
modalRef.current.update(newConfig);
|
updateAction();
|
||||||
|
} else {
|
||||||
|
setActionQueue(prev => [...prev, updateAction]);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user