如何在 React 中管理弹窗状态:三种方法的示例
在 React 中管理弹窗的状态有多种方法。本文将介绍三种常用的方法,并通过简单的示例代码进行演示。这三种方法分别是:
- 使用存储 State 更新函数的引用
- 使用 Context API
- 使用 React.forwardRef 和 useImperativeHandle
方法一:使用存储 State 更新函数的引用
这种方法通过在全局存储 State 更新函数的引用来控制弹窗的显示和隐藏。下面是一个简单的示例:
import React, { useState, useEffect } from 'react';
import { Modal, Button } from 'antd';
// 定义一个对象来存储弹窗状态
interface ModalState {
visible: boolean;
applyId: number | null;
ruleId: number | null;
}
// 全局引用存储 State 更新函数
let setModalStateRef: React.Dispatch<React.SetStateAction<ModalState>> | null = null;
export function toggleModal(visible: boolean, applyId?: number, ruleId?: number) {
if (setModalStateRef) {
setModalStateRef((prev) => ({
...prev,
visible,
applyId: visible ? applyId ?? null : null,
ruleId: visible ? ruleId ?? null : null,
}));
}
}
const ModalComponent: React.FC = () => {
const [modalState, setModalState] = useState<ModalState>({
visible: false,
applyId: null,
ruleId: null,
});
useEffect(() => {
setModalStateRef = setModalState;
return () => {
setModalStateRef = null;
};
}, []);
const handleCancel = () => {
setModalState((prev) => ({
...prev,
visible: false,
applyId: null,
ruleId: null,
}));
};
return (
<Modal visible={modalState.visible} onCancel={handleCancel}>
<p>申请ID: {modalState.applyId}</p>
<p>规则ID: {modalState.ruleId}</p>
</Modal>
);
};
const App: React.FC = () => {
return (
<div>
<Button onClick={() => toggleModal(true, 123, 456)}>显示弹窗</Button>
<Button onClick={() => toggleModal(false)}>隐藏弹窗</Button>
<ModalComponent />
</div>
);
};
export default App;
方法二:使用 Context API
Context API 适用于在整个组件树中共享状态。下面是一个简单的示例:
import React, { createContext, useContext, useState, ReactNode } from 'react';
import { Modal, Button } from 'antd';
interface ModalState {
visible: boolean;
applyId: number | null;
ruleId: number | null;
}
interface ModalContextType {
modalState: ModalState;
setModalState: React.Dispatch<React.SetStateAction<ModalState>>;
}
const ModalContext = createContext<ModalContextType | undefined>(undefined);
const ModalProvider = ({ children }: { children: ReactNode }) => {
const [modalState, setModalState] = useState<ModalState>({
visible: false,
applyId: null,
ruleId: null,
});
return (
<ModalContext.Provider value={{ modalState, setModalState }}>
{children}
</ModalContext.Provider>
);
};
const useModal = () => {
const context = useContext(ModalContext);
if (!context) {
throw new Error('useModal must be used within a ModalProvider');
}
return context;
};
const ModalComponent: React.FC = () => {
const { modalState, setModalState } = useModal();
const handleCancel = () => {
setModalState({
visible: false,
applyId: null,
ruleId: null,
});
};
return (
<Modal visible={modalState.visible} onCancel={handleCancel}>
<p>申请ID: {modalState.applyId}</p>
<p>规则ID: {modalState.ruleId}</p>
</Modal>
);
};
const App: React.FC = () => {
const { setModalState } = useModal();
const showModal = () => {
setModalState({
visible: true,
applyId: 123,
ruleId: 456,
});
};
const hideModal = () => {
setModalState({
visible: false,
applyId: null,
ruleId: null,
});
};
return (
<div>
<Button onClick={showModal}>显示弹窗</Button>
<Button onClick={hideModal}>隐藏弹窗</Button>
<ModalComponent />
</div>
);
};
const AppWrapper: React.FC = () => {
return (
<ModalProvider>
<App />
</ModalProvider>
);
};
export default AppWrapper;
方法三:使用 React.forwardRef 和 useImperativeHandle
这种方法通过 ref 将子组件的方法暴露给父组件。下面是一个简单的示例:
import React, { useState, useImperativeHandle, forwardRef, useRef } from 'react';
import { Modal, Button } from 'antd';
interface ModalState {
visible: boolean;
applyId: number | null;
ruleId: number | null;
}
interface ModalHandle {
toggleModal: (visible: boolean, applyId?: number, ruleId?: number) => void;
}
const ModalComponent = forwardRef<ModalHandle>((_, ref) => {
const [modalState, setModalState] = useState<ModalState>({
visible: false,
applyId: null,
ruleId: null,
});
useImperativeHandle(ref, () => ({
toggleModal(visible, applyId, ruleId) {
setModalState({
visible,
applyId: visible ? applyId ?? null : null,
ruleId: visible ? ruleId ?? null : null,
});
},
}));
const handleCancel = () => {
setModalState({
visible: false,
applyId: null,
ruleId: null,
});
};
return (
<Modal visible={modalState.visible} onCancel={handleCancel}>
<p>申请ID: {modalState.applyId}</p>
<p>规则ID: {modalState.ruleId}</p>
</Modal>
);
});
const App: React.FC = () => {
const modalRef = useRef<ModalHandle>(null);
const showModal = () => {
modalRef.current?.toggleModal(true, 123, 456);
};
const hideModal = () => {
modalRef.current?.toggleModal(false);
};
return (
<div>
<Button onClick={showModal}>显示弹窗</Button>
<Button onClick={hideModal}>隐藏弹窗</Button>
<ModalComponent ref={modalRef} />
</div>
);
};
export default App;
结论
这三种方法各有优劣:
- 存储 State 更新函数的引用:适用于简单的状态管理,代码易于理解和维护。
- Context API:适用于需要在多个组件间共享状态的场景,提供了灵活的状态管理能力。
- React.forwardRef 和 useImperativeHandle:适用于父组件需要直接控制子组件行为的场景,提供了清晰的接口。
选择哪种方法取决于具体的需求和项目架构。希望本文的示例代码能帮助您更好地理解和选择适合的方法来管理 React 中的弹窗状态。
评论
使用 GitHub 账号登录后即可评论