使用 @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>
  );
}
sample01.gif

现在还是在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>
    </>
  );
}
changed.gif

通过以上方法,现在可以从其他组件中管理MessageModal的状态,并且能够轻松地对MessageModal进行开/关操作。

广告
将在 10 秒后关闭
bannerAds