[英]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
狀態。 這將始終導致無限重新渲染。
逐字回答您的問題:“如何僅在數據更改時才重新渲染?”
由於rooms
和data
設置為相同,您可以保持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.