React/Django 中状态未正确更新的问题

Issues with states not updating correctly in React/Django

建立一个用户上传的网站images/video,在处理这个的组件中,我让图片在上传后加载到页面中,这样用户就可以确定他们想要post 他们,如果他们愿意,可以选择删除它们。我最初将其作为 Class-based 视图,一切都按预期工作,但现在,在更改为功能组件后,上传图像后,React 似乎没有注意到 imageLinks 的变化(即使控制台显示imageLinks 被添加到),直到我更新 post 标题等其他内容,然后它们都会按预期加载。加载后,如果我单击删除按钮,React 会立即更新并且 photos/videos 不再显示,如预期的那样。

关于为什么这表现如此奇怪有什么想法吗? deleteMedia 函数工作正常的事实让我很奇怪。

我这样设置我的变量

export default function NewPost(props) {
  const [postCategories, setPostCategories] = useState([]);
  const [postTitle, setPostTitle] = useState();
  const [postDescription, setPostDescription] = useState();
  const [postHashtags, setPostHashtags] = useState();
  const [imageLinks, setImageLinks] = useState([]);
...}

在我的组件中,我有这个来处理上传和删除文件。

const uploadMedia = async (file) => {
    var csrftoken = getCookie("csrftoken");
    var media_id = makeMediaID();
    let formData = new FormData();
    formData.append("content_id", contentID);
    formData.append("creator_id", USER_ADDRESS);
    formData.append("content_media", file);
    formData.append("media_id", media_id);
    const response = await fetch("/api/newpost/media/", {
      method: "POST",
      headers: {
        "X-CSRFToken": csrftoken,
      },
      body: formData,
    });
    console.log(response);
    const r_json = await response.json();
    if (r_json.success) {
      let tempLinks = imageLinks;
      tempLinks.push({
        img: r_json.image_url,
        id: r_json.m_id,
        type: r_json.m_type,
      });
      setImageLinks(tempLinks);
      console.log(imageLinks);
    } else {
      console.log(r_json.message);
    }
  };
  
  const deleteMedia = async (media) => {
    var csrftoken = getCookie("csrftoken");
    let formData = new FormData();
    formData.append("media_id", media);
    formData.append("creator_id", USER_ADDRESS);
    const response = await fetch("/api/newpost/media/delete/", {
      method: "DELETE",
      headers: {
        "X-CSRFToken": csrftoken,
      },
      body: formData,
    });
    console.log(response);
    const r_json = await response.json();
    if (r_json.success) {
      let tempLinks = imageLinks.filter((item) => item.id !== media);
      setImageLinks(tempLinks);
    } else {
      console.log("Media deletion error");
    }
  };

在我的渲染中,我有这个,当它是一个 class-based 组件时它工作得很好。

{imageLinks.map((item) => (
                  <Grid item xs={9} align="center" key={item.img}>
                    <Card style={{ maxWidth: 550, margin: 15 }}>
                      <div
                        style={{
                          display: "flex",
                          alignItem: "center",
                          justifyContent: "center",
                        }}
                      >
                        <CardMedia
                          style={{
                            width: "100%",
                            maxHeight: "550px",
                          }}
                          component={item.type}
                          image={item.img}
                          controls
                          title={String(item.img)}
                        />
                      </div>
                      <div align="center">
                        <CardActions>
                          <Button
                            endIcon={<DeleteForeverIcon />}
                            label="DELETE"
                            color="secondary"
                            variant="contained"
                            onClick={() => deleteMedia(item.id)}
                          >
                            REMOVE
                          </Button>
                        </CardActions>
                      </div>
                    </Card>
                  </Grid>
                ))}

问题

问题是状态突变。

const [imageLinks, setImageLinks] = useState([]);

tempLinks 是对 imageLinks 状态的引用。您直接推入此 tempLinks 数组并将相同的数组引用保存回状态。该代码还错误地尝试在将状态更新加入队列后立即记录状态。这不起作用,因为 React 状态更新是异步处理的。

if (r_json.success) {
  let tempLinks = imageLinks; // <-- reference to state
  tempLinks.push({            // <-- state mutation!
    img: r_json.image_url,
    id: r_json.m_id,
    type: r_json.m_type,
  });
  setImageLinks(tempLinks);   // <-- same reference back into state
  console.log(imageLinks);    // <-- only logs current state
}

imageLinks 状态数组引用永远不会改变,因此 React 不会将其视为实际正在更新的状态。

解决方案

为 React 创建并 return 一个 new 数组引用。

if (r_json.success) {
  setImageLinks(imageLinks => [ // <-- new array reference
    ...imageLinks,              // <-- shallow copy previous state
    {                           // <-- append new element object
      img: r_json.image_url,
      id: r_json.m_id,
      type: r_json.m_type,
    }
  ]);
}

使用单独的 useEffect 挂钩来控制台记录状态更新。

useEffect(() => {
  console.log(imageLinks);
}, [imageLinks]);