簡體   English   中英

數據更改后如何使useEffect重新渲染?

[英]How to make useEffect rerender after the data is changed?

我希望 useEffect 獲取和渲染rooms數據。 並在新房間添加到rooms時重新渲染數據

使用 useEffect 和空依賴項獲取數據和顯示數據的代碼。

const [rooms, setRooms] = useState([]);

  const getRoomsData = async () => {
    const querySnapshot = await getDocs(collection(db, "rooms"));
    const data = querySnapshot.docs.map((doc) => ({
      id: doc.id,
      data: doc.data(),
    }));

    setRooms(data);
  };

  useEffect(() => {
    getRoomsData();
    console.log("rerendered");
  }, []);

使用此代碼,在我將新房間添加到rooms 我需要手動刷新頁面以查看呈現的新數據。 在將新“房間”添加到rooms后,我應該怎么做才能使其重新呈現?

添加房間的代碼:

    const roomName = prompt("please enter name for chat room");

    if (roomName) {
      addDoc(collection(db, "rooms"), {
        name: roomName,
      });
    }
  };

我嘗試向 useEffect 依賴項添加房間,這有我想要的結果(無需刷新),但這只是因為它無限渲染,這很糟糕。 正確的做法是什么?

您將獲得無限的重新渲染,因為useEffect的函數正在更新效果依賴數組中的rooms狀態。 這將始終導致無限重新渲染。

逐字回答您的問題:“如何僅在數據更改時才重新渲染?”

由於roomsdata設置為相同,您可以保持useEffect ,但隨后創建另一個useEffect以僅在組件安裝調用getRoomsData()

const [rooms, setRooms] = useState([]);

  const getRoomsData = async () => {
    const querySnapshot = await getDocs(collection(db, "rooms"));
    const data = querySnapshot.docs.map((doc) => ({
      id: doc.id,
      data: doc.data(),
    }));

    setRooms(data);
  };

  useEffect(() = > {
    getRoomsData();
  }, [])

  useEffect(() => {
    console.log("rerendered");
  }, [rooms]);

我認為解決您的問題的真正關鍵是知道何時調用getRoomsData() ,因為根據這一點,您將更改useEffect依賴項數組以適應該需要。

使用 useEffect 獲取數據時,它期望進行同步調用。 從 Firestore 請求數據將是異步的,因此為了解決這個問題,我們可以添加一個函數來包裝名為 getRoomsData 的 firestore 調用,如下所示:

 const [rooms, setRooms] = useState([]); useEffect(() = > { const getRoomsData = async () => { const querySnapshot = await getDocs(collection(db, "rooms")); const data = querySnapshot.docs.map((doc) => ({ id: doc.id, data: doc.data(), })); setRooms(data); }; getRoomsData(); }, [])

我可以想到兩種解決這個問題的方法,而不必使用useEffect ,第一種是一種解決方法,您可以在本地更新rooms狀態而不必從服務器獲取它,即,您基本上是在構建對象並將其附加到現有的rooms數組,只有當您知道對象的結構時才有可能,查看您的getRoomsData函數,您似乎正在返回一個數據數組,其中每個項目都具有以下對象結構。

{
 id: <DOCUMENT_ID>,
 data: {
  name: <ROOM_NAME>
 }
}

因此,當您添加房間時,您可以執行以下操作:

   const roomName = prompt("please enter name for chat room");

    if (roomName) {
      addDoc(collection(db, "rooms"), {
        name: roomName,
      });
      let newRoom = {
        id: Math.random(), //random id
        data: {
          name: roomName
        }
      }
      setRooms([...rooms,newRoom])
  };

通過這種方式,您還可以減少網絡調用的數量,這是一個性能獎勵,但唯一的缺點是您必須確定對象結構,以便相應地繪制結果。
如果您不確定對象結構,您可以做的是在將新房間添加到集合后調用getRoomsData ,如下所示:

   const roomName = prompt("please enter name for chat room");

    if (roomName) {
      addDoc(collection(db, "rooms"), {
        name: roomName,
      }).then(res=>{
          getRoomsData();
      })
  };

這將確保獲取最新數據(包括最近添加的房間)並使用所有結果呈現您的組件。 在您遵循的任一方法中,當組件使用空依賴項數組掛載時,您只能使用一次useEffect

 useEffect(() => {
    getRoomsData();
    //console.log("rerendered");
  }, []);

通過這樣做,您首先基本上顯示用戶第一次訪問此頁面時/第一次安裝組件時的數據。 在后續添加時,您可以在將新添加的room添加到數據庫后將其作為對象附加到rooms數組,或者將其添加到數據庫並再次獲取所有結果,以便在屏幕上呈現最新添加的rooms

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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