使用 @tanstack/react-query 来管理模态框的状态
我打算在React的前端应用程序中介绍使用@tanstack/react-query(以下简称react-query)进行状态管理的方法,并尝试创建一个显示消息的模态框。
开发环境
节点: 16.15.0
电脑: 苹果(mac版本11.7.1)
"vite": "^4.3.9"
"react": "^18.2.0",
"react-dom": "^18.2.0"
"typescript": "^5.0.2",
"@tanstack/react-query": "^4.29.12",
"@mui/material": "^5.13.4",
"@emotion/react": "^11.11.0",
"@emotion/styled": "^11.11.0",
使用react-query进行状态管理的方法
最初的设定
安装软件包。
使用yarn命令,以开发环境的方式将@tanstack/react-query安装到项目中。
设置提供者。
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import "./index.css";
+ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
+ const client = new QueryClient({
+ defaultOptions: {
+ queries: {
+ enabled: false,
+ },
+ },
+ });
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
<React.StrictMode>
+ <QueryClientProvider client={client}>
<App />
+ </QueryClientProvider>
</React.StrictMode>
);
在创建 QueryClient 实例时,通过设置 defaultOptions.queries.enabled: false 来抑制数据 fetch。因此,如果你想要使用 react-query 进行数据 fetch,请按照下面的方法进行设置。
使用react-query进行状态管理的方法
设定数据
type UserState = {
name: string;
};
const queryClient = useQueryClient()
queryClient.setQueryData<UserState>(["user-state"], {name: "John"})
提取数据
const data = useQuery<UserState>(["user-state"]).data;
console.log(data && data.user); // John
在React组件或自定义钩子函数中以这种方式编写的代码,可以在不同的组件之间设置和提取{name: “John”}的数据。
重要的是,queryClient.setQueryData 和 useQuery 的第一个参数 QueryKey 的值要相同。
同样,如果在使用先前提到的react-query进行数据获取时,不写入默认选项”main.tsx”的QueryClient,并在获取时进行以下设置,则可以抑制数据的获取:”queries.enabled: false”。
const data = useQuery(["query-key"], {
enabled: false,
}).data;
管理消息模态的状态
信息模态框组件
使用 Material-UI 创建一个 MessageModal 组件。
import { Box, Button, Typography, Modal } from "@mui/material";
export const MessageModal = () => {
return (
<div>
<Button onClick={handleOpen}>Open modal</Button>
<Modal
open={open}
onClose={handleClose}
>
<Box>
<Typography variant="h6" component="h2">
Message Modal
</Typography>
</Box>
</Modal>
</div>
);
}
现在还是在MessageModal组件内进行状态管理。
创建一个管理状态的自定义钩子
我們將在自定義鉤子中管理 MessageModal 的開啟/關閉狀態和顯示的文本。
type ModalState = {
isOpen: boolean;
message: string;
}
另外,开启模态时最好设置一些文本内容,因此我们将同时设置在打开模态时显示的文本内容。
如果自定义钩子的返回值类型符合以下情况,则可以。
type ReturnType = {
isOpen: boolean;
message: string;
open: (message: string) => void;
close: () => void;
}
创建一个自定义钩子,该钩子可以调用开启/关闭函数open和close以及变量isOpen和要显示在模态框中的文本message。
export function useModalState(): ReturnType {
const queryClient = useQueryClient();
// initialDataを設定しないと戻り値の型がundefinedになる
const { message, isOpen } = useQuery<ModalState>(["modal-state"], {
initialData: {
isOpen: false,
message: "",
},
}).data;
const open = (message: string) => {
queryClient.setQueryData<ModalState>(["modal-state"], {
isOpen: true,
message,
});
};
const close = () => {
queryClient.setQueryData<ModalState>(["modal-state"], {
isOpen: false,
message: "",
});
};
return { isOpen, message, open, close };
}
我们可以将定制的钩子用于 MessageModal 组件以及想要显示 MessageModal 组件的组件中。
export const MessageModal = () => {
const { isOpen, message, close } = useModalState();
const handleClose = () => close();
if (!isOpen) {
return null;
}
return (
<div>
<Modal
open={isOpen}
onClose={handleClose}
>
<Box sx={style}>
<Typography variant="h6" component="h2">
{message}
</Typography>
<Button onClick={handleClose}>モーダルを閉じる</Button>
</Box>
</Modal>
</div>
);
};
import { MessageModal } from "./MessageModal";
import { useModalState } from "./useModalMessage";
const ChildA: React.FC = () => {
const { open } = useModalState();
return (
<div>
<p>A コンポーネント</p>
<button onClick={() => open("This is A Component.")}>
モーダルを開く
</button>
</div>
);
};
const ChildB: React.FC = () => {
const { open } = useModalState();
return (
<div>
<p>B コンポーネント</p>
<button onClick={() => open("This is B Component.")}>
モーダルを開く
</button>
</div>
);
};
function App() {
const { open } = useModalState();
return (
<>
<MessageModal />
<div>
<h1>Hello, React</h1>
<button onClick={() => open("モーダルを開きました。")}>
モーダルを開く
</button>
<ChildA />
<ChildB />
</div>
</>
);
}
通过以上方法,现在可以从其他组件中管理MessageModal的状态,并且能够轻松地对MessageModal进行开/关操作。