簡體   English   中英

如何訪問已調用setState的函數體中的更新狀態?

[英]How to access the updated state in the body of a function that has already called setState?

我目前正在編寫一個函數來將blogPost對象保存到我的Firestore數據庫中的document中。

預期的例程應該是:

  • 單擊SAVE按鈕並調用savePost()函數
  • savePost()函數應調用uploadImagesAndGetURL()函數,因為在將src URL保存到Firestore之前, blogPost的圖像上傳到Firebase存儲。 (在我的實際情況中,圖像上傳是async ,我await它完成,但我不認為這會傷害這里的例子)。
  • uploadImagesAndGetURL()應該上傳圖像並將返回的urls存儲在各自的src屬性中, stateelements數組中。
  • 它通過在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鈎子中的保存邏輯,它會觸發運行效果。

繼續 編輯so.answer.56544887

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM