3

我正在从我的快递后端获取并显示一系列帖子,它显示为“博客”组件。

帖子列表

该组件有一个从后端删除它然后重新获取帖子的按钮,每当我单击删除按钮时,状态会从“空闲”变为“加载”再到“成功”,然后在重新获取数据时将其删除。

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

帖子“标题2”被删除,帖子3显示状态为“成功”

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;

登陆.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);
});
4

1 回答 1

3

有两个要点可以理解发生了什么:

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

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

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

查看Robin Pokorny 的文章,深入解释使用索引作为键的负面影响。

于 2020-11-08T21:30:41.797 回答