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]);
建立一个用户上传的网站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]);