[英]How to access the updated state in the body of a function that has already called setState?
我目前正在编写一个函数来将blogPost
对象保存到我的Firestore数据库中的document
中。
预期的例程应该是:
savePost()
函数 savePost()
函数应调用uploadImagesAndGetURL()
函数,因为在将src
URL保存到Firestore之前, blogPost
的图像上传到Firebase存储。 (在我的实际情况中,图像上传是async
,我await
它完成,但我不认为这会伤害这里的例子)。 uploadImagesAndGetURL()
应该上传图像并将返回的urls
存储在各自的src
属性中, state
的elements
数组中。 elements
数组上运行forEach()
并调用setState()
(setBlogPost)以使用从存储接收的新URL更新状态来实现。 saveToFirestore()
函数,并且应该能够访问最新状态,以便能够将blogPost
对象与图像src's
一起保存到数据库中。 题
我的问题是,当我运行savePost()
函数时,在这种情况下组件被重新渲染3次(对于3个图像),因为uploadImagesAndGetURL()
正在调用setBlogPost()
3次。 每个图像一个。 当我到达saveToFirestore()
函数并记录blogPost
状态时,您可以看到只有第一个图像src
已更改。
我做得对吗? 在saveToFirestore()
之前,如何改进此例程以确保所有内容都已更新?
注意:一种方法是跳过状态更新并将返回的URL直接传递给saveToFirestore()
函数,而不将它们存储在状态中。 但是,在这种情况下,适当的模式是什么?
从saveToFirestore()
函数记录:
{
"title": "This is the title",
"body": "Click on the button to upload this post",
"elements": [
{
"type": "image",
"src": "source0"
},
{
"type": "image",
"src": null
},
{
"type": "image",
"src": null
}
]
}
下面是SNIPPET
function App() { console.log('Rendering App...'); const [blogPost,setBlogPost] = React.useState({ title: 'This is the title', body: 'Click on the button to upload this post', elements: [ { type: 'image', src: null }, { type: 'image', src: null }, { type: 'image', src: null } ] }); function savePost() { console.log('Inside savePost'); uploadImagesAndGetURL(); saveToFirestore(); } function uploadImagesAndGetURL() { console.log('Inside uploadImages'); blogPost.elements.forEach((item,index) => { console.log('Inside uploadImages - forEach'); setBlogPost((prevState)=>{ const aux = Array.from(prevState.elements); aux[index].src = 'source' + index; return({ ...prevState, elements: aux }); }); }); } function saveToFirestore() { console.log('Inside saveToFirestore'); console.log('Will save the following blogPost to Firestore'); console.log(blogPost); } return( <React.Fragment> <div>{blogPost.title}</div> <div>{blogPost.body}</div> <div>Image 1 src: {blogPost.elements[0].src}</div> <div>Image 2 src: {blogPost.elements[1].src}</div> <div>Image 3 src: {blogPost.elements[2].src}</div> <button onClick={savePost}>Save Post</button> </React.Fragment> ); } ReactDOM.render(<App/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script> <div id="root"></div>
您可以在更改博客状态时移动useEffect
钩子中的保存逻辑,它会触发运行效果。
import React, { useEffect } from "react";
import ReactDOM from "react-dom";
function App() {
console.log("Rendering App...");
const [blogPost, setBlogPost] = React.useState({
title: "This is the title",
body: "Click on the button to upload this post",
elements: [
{ type: "image", src: null },
{ type: "image", src: null },
{ type: "image", src: null }
]
});
function savePost() {
console.log("Inside savePost");
uploadImagesAndGetURL();
// saveToFirestore();
}
function uploadImagesAndGetURL() {
console.log("Inside uploadImages");
const elements = blogPost.elements.map((_, index) => ({
type: "image",
src: `source${index}`
}));
setBlogPost(previousPost => ({ ...previousPost, elements }));
}
// function uploadImagesAndGetURL() {
// console.log("Inside uploadImages");
// blogPost.elements.forEach((item, index) => {
// console.log("Inside uploadImages - forEach");
// setBlogPost(prevState => {
// const aux = Array.from(prevState.elements);
// aux[index].src = "source" + index;
// return {
// ...prevState,
// elements: aux
// };
// });
// });
// }
useEffect(() => {
function saveToFirestore() {
console.log("Inside saveToFirestore");
console.log("Will save the following blogPost to Firestore");
console.log(blogPost);
}
saveToFirestore();
}, [blogPost]);
return (
<React.Fragment>
<div>{blogPost.title}</div>
<div>{blogPost.body}</div>
<div>Image 1 src: {blogPost.elements[0].src}</div>
<div>Image 2 src: {blogPost.elements[1].src}</div>
<div>Image 3 src: {blogPost.elements[2].src}</div>
<button onClick={savePost}>Save Post</button>
</React.Fragment>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
uploadImagesAndGetURL()调用setBlogPost()3次。
而且我实际上得到了URL列表并一次设置了elements
属性以防止重新渲染3次。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.