[英]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.