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 CSSMotion from 'rc-motion';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { genCSSMotion } from 'rc-motion/lib/CSSMotion';
|
||||
import { mount } from 'enzyme';
|
||||
import Modal from '..';
|
||||
@ -48,15 +49,19 @@ describe('Modal.hook', () => {
|
||||
expect(wrapper.find('.ant-modal-body').length).toBeTruthy();
|
||||
|
||||
// Update instance
|
||||
act(() => {
|
||||
instance.update({
|
||||
content: <div className="updated-content" />,
|
||||
});
|
||||
});
|
||||
wrapper.update();
|
||||
expect(wrapper.find('.updated-content')).toHaveLength(1);
|
||||
|
||||
// Destroy
|
||||
act(() => {
|
||||
instance.destroy();
|
||||
jest.runAllTimers();
|
||||
});
|
||||
wrapper.update();
|
||||
expect(wrapper.find('Modal')).toHaveLength(0);
|
||||
|
||||
@ -100,4 +105,62 @@ describe('Modal.hook', () => {
|
||||
wrapper.find('.ant-modal-wrap').simulate('click');
|
||||
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] {
|
||||
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(
|
||||
(withFunc: (config: ModalFuncProps) => ModalFuncProps) =>
|
||||
function hookConfirm(config: ModalFuncProps) {
|
||||
@ -57,13 +72,25 @@ export default function useModal(): [Omit<ModalStaticFunctions, 'warn'>, React.R
|
||||
|
||||
return {
|
||||
destroy: () => {
|
||||
function destroyAction() {
|
||||
modalRef.current?.destroy();
|
||||
}
|
||||
|
||||
if (modalRef.current) {
|
||||
modalRef.current.destroy();
|
||||
destroyAction();
|
||||
} else {
|
||||
setActionQueue(prev => [...prev, destroyAction]);
|
||||
}
|
||||
},
|
||||
update: (newConfig: ModalFuncProps) => {
|
||||
function updateAction() {
|
||||
modalRef.current?.update(newConfig);
|
||||
}
|
||||
|
||||
if (modalRef.current) {
|
||||
modalRef.current.update(newConfig);
|
||||
updateAction();
|
||||
} else {
|
||||
setActionQueue(prev => [...prev, updateAction]);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user