React Hooks:在卸装返回初始状态之前尝试访问状态

时间:2019-04-11 15:22:02

标签: reactjs

通常,我在尝试卸载组件时会尝试保存全局状态更新,因为react-apollo使我很难进行不必要的重新提取。

我正在将所有已删除的注释ID添加到deletedCommentsQueue,并且当Comments组件卸载时,我想更新我的全局状态,但是当要卸载的deletedCommentsQueue组件更改为空数组,即使我们在尝试进行更新之前可以看到所有评论ID。

我为你们做了一个简单的SandBox

这是我给有兴趣的人的代码

import React, { useState, useEffect, useContext, createContext } from "react";
import ReactDOM from "react-dom";

import "./styles.css";

const UserContext = createContext();

const comments = [
  { _id: 1, body: "first" },
  { _id: 2, body: "second" },
  { _id: 3, body: "third" }
];

const Comments = ({ commentIds }) => {
  const [deletedCommentsQueue, setDeletedCommentsQueue] = useState([]);

  const addToQueue = commentId => {
    setDeletedCommentsQueue([...deletedCommentsQueue, commentId]);
  };

  const { loggedUser, setLoggedUser } = useContext(UserContext);

  useEffect(
    () => () => {
      console.log("cleaning");
      console.log("deletedCommentsQueue", deletedCommentsQueue);

      const updatedComments = loggedUser.comments.filter(
        commentId => !deletedCommentsQueue.includes(commentId)
      );

      console.log(updatedComments);

      setLoggedUser({
        ...loggedUser,
        comments: updatedComments,
        likes: {
          ...loggedUser.likes,
          comments: loggedUser.likes.comments.filter(
            commentId => !deletedCommentsQueue.includes(commentId)
          )
        }
      });
    },
    []
  );

  return (
    <div>
      {deletedCommentsQueue.length > 0 && (
        <h1>Comment ids for deletion {deletedCommentsQueue.join(" ")}</h1>
      )}
      {commentIds.map(commentId => (
        <Comment
          deleted={deletedCommentsQueue.includes(commentId)}
          key={commentId}
          comment={comments.find(c => c._id === commentId)}
          deleteCommentFromCache={() => addToQueue(commentId)}
        />
      ))}
    </div>
  );
};

const Comment = ({ comment, deleted, deleteCommentFromCache }) => (
  <div>
    {deleted && <h2>Deleted</h2>}
    <p>{comment.body}</p>
    <button disabled={deleted} onClick={deleteCommentFromCache}>
      Delete
    </button>
  </div>
);

const App = () => {
  const [loggedUser, setLoggedUser] = useState({
    username: "asafaviv",
    comments: [1, 2, 3],
    likes: {
      comments: [1, 2]
    }
  });

  const [mounted, setMounted] = useState(true);

  return (
    <div className="App">
      <UserContext.Provider value={{ loggedUser, setLoggedUser }}>
        {mounted && <Comments commentIds={loggedUser.comments} />}
      </UserContext.Provider>
      <br />
      <button onClick={() => setMounted(!mounted)}>
        {mounted ? "Unmount" : "Mount"}
      </button>
    </div>
  );
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

1 个答案:

答案 0 :(得分:0)

我猜这是因为您声明的效果具有空依赖性([])。这样,在安装组件时,效果将运行一次。

因此,我想在其关闭的上下文中,deletedCommentQueues的值等于首次安装该组件的时间=> []

我尝试了您的codeandbox,如果您删除了[](这意味着每次更新都会调用该效果),则在卸载组件时会获得正确的值,但是...每次更新都会调用该函数不能解决您的缓存问题。

恕我直言,我建议您在父组件中设置状态(const [deletedCommentsQueue, setDeletedCommentsQueue] = useState([]);,并在mounted值变为false而不是的时候将数据保存到所需的任何位置从组件内部观看。