每当我在更改映射组件后重新获取反应查询时,下一个组件的更改状态显示为 "success"

Whenever i refetch in react query after mutating a mapped component, the status of the mutation of the next component shows as "success"

我正在从我的 express 后端获取并显示一个 post 数组,它显示为“博客”组件。

list of posts

该组件有一个按钮可以从后端删除它,然后重新获取 posts,每当我点击删除按钮时,状态从“空闲”变为“加载”再变为“成功”并且然后在重新获取数据时将其删除。

这行得通,但是当它被删除时,下一个 post 显示“成功”作为状态。为什么?

post "title 2" is deleted and post 3 displays status as "success"

BlogPost.jsx:

import React from "react";
import axios from "axios";
import { useQueryCache, useMutation } from "react-query";

const deleteBlog = ({ postID }) => {
  return axios.delete(`/api/posts/${postID}`, { withCredentials: true });
};

const BlogPost = ({ postID, title, content }) => {
  const [mutation, { status }] = useMutation(deleteBlog);
  const queryCache = useQueryCache();

  return (
    <div style={{ border: "medium solid red", padding: 5 }}>
      {`status: ${status}`}
      <button
        onClick={() => {
          mutation({ postID }).then(() => {
            queryCache.invalidateQueries("posts");
          });
        }}
      >
        delete
      </button>
      <h2>{title}</h2>
      <h3>{postID}</h3>
      <p>{content}</p>
    </div>
  );
};

export default BlogPost;

Landing.jsx:

import React from "react";
import BlogPost from "../components/BlogPost";
import axios from "axios";
import { useQuery } from "react-query";

const posts = () => {
  return axios.get("/api/posts").then((resp) => resp.data);
};

const Landing = () => {
  const { data, isSuccess, refetch } = useQuery("posts", posts);

  return (
    <div>
      <button
        onClick={() =>
          axios
            .post(
              "/api/posts",
              { title: "title", content: "content" },
              { withCredentials: true }
            )
            .then(() => refetch())
        }
      >
        New post
      </button>

      {isSuccess &&
        data.map((post, index) => {
          return (
            <BlogPost
              key={index}
              postID={post._id}
              title={post.title}
              createdDate={post.createdAt}
              author={post.author}
              content={post.content}
            />
          );
        })}
    </div>
  );
};

export default Landing;

快递后端:

let fakedb = [
  {
    _id: "0",
    title: "title",
    createdAt: "1234",
    author: "Lorem",
    content: "453",
  },
];

app.get("/api/posts", (req, res) => {
  res.json(fakedb);
});

app.post("/api/posts", (req, res) => {
  const { title, content } = req.body;
  fakedb.push({
    title,
    _id: fakedb.length.toString(),
    content,
    createdAt: "456",
    author: "1",
  });
  res.sendStatus(200);
});

app.delete("/api/posts/:postID", (req, res) => {
  fakedb = fakedb.filter((i) => i._id !== req.params.postID);
  res.sendStatus(200);
});

有两个要点可以理解正在发生的事情:

  • status是变异请求的状态
  • Landing.jsx 使用索引作为 BlogPost 组件的键。

键是 React 唯一用来识别 DOM 元素的东西。在删除操作后重新获取数据时,现在响应数据是一个包含 3 个博客 post 对象的数组。因为您使用索引作为键,React 认为数组中的第 3 个元素(在索引 3 之前但现在是索引 2)与之前的元素相同。由于道具不同,它 re-render 组件。此时组件保持着之前操作的状态。

React documentation警告不要使用键,因为它会显示错误的数据。

查看 Robin Pokorny’s article 以获得关于使用索引作为键的负面影响的 in-depth 解释。