[英]useEffect overriding the state instead of appending the values while making firestore calls
const [data, setData] = useState([])
const getDataFromFirebase = async () => {
let response = await firestore.collection('someDatabase').get()
response.forEach(item => setData([...data, item.data().name]))
}
useEffect(() => {
getDataFromFirebase()
},[])
data is being overridden with the latest value instead of adding all the values to the array. data 被最新值覆盖,而不是将所有值添加到数组中。
Use the callback in setData
在
setData
中使用回调
setData(prevState => ([
...prevState, item.data().name
]));
The reason is time taken to add item is very less thats why before reflecting, it got override.原因是添加项目所花费的时间非常少,这就是为什么在反映之前,它被覆盖了。 You have to use prevState in setData.
您必须在 setData 中使用 prevState。 Try this:
尝试这个:
const [data, setData] = useState([]) const getDataFromFirebase = async () => { let response = await firestore.collection('someDatabase').get() response.forEach(item => setData(prevState => ([...prevState, item.data().name]) ); } useEffect(() => { getDataFromFirebase() },[])
let response = await firestore.collection('someDatabase').get()
response.forEach(item => setData([...data, item.data().name]))
I'm not familiar with firestore
, but that promise will be resolved once, and you should do something like this instead:我不熟悉
firestore
,但 promise 将被解决一次,你应该这样做:
const dataToAdd = response.map(item => item.data().name)
setData(prevState => ([...prevState, ...dataToAdd])
You are rerending component each time the setData
is being called and you shouldn't do it in a synced loop.每次调用
setData
时,您都会重新渲染组件,并且您不应该在同步循环中执行此操作。
prevState
is necessary here because you are working in an asynchronous function. prevState
在这里是必要的,因为您正在异步 function 中工作。 In theory, it should work without it after using a solution with dataToAdd
if you don't change the state anywhere else.从理论上讲,如果您不在其他任何地方更改 state,则在使用带有
dataToAdd
的解决方案后,它应该可以在没有它的情况下工作。
try this fire setState once but build the array before:尝试此触发 setState 一次,但在此之前构建数组:
const [data, setData] = useState([])
const getDataFromFirebase = async () => {
let response = await firestore.collection('someDatabase').get()
const d = response.map(item=> item.data().name)
setData(d)
}
useEffect(() => {
getDataFromFirebase()
},[])
firing setData
multiple times will cause multiple rerenders so here it's fire once.多次触发
setData
会导致多次重新渲染,所以这里只触发一次。
In your code below the value of data will be always []
even if you change the data later.在您下面的代码中,即使您稍后更改数据,数据的值也将始终为
[]
。
const getDataFromFirebase = async () => {
let response = await firestore.collection('someDatabase').get()
response.forEach(item => setData([...data, item.data().name]))
}
This is what docs say about it这就是文档所说的
Mutations, subscriptions, timers, logging, and other side effects are not allowed inside the main body of a function component (referred to as React's render phase).
function 组件(称为 React 的渲染阶段)的主体中不允许发生突变、订阅、计时器、日志记录和其他副作用。 Doing so will lead to confusing bugs and inconsistencies in the UI.
这样做会导致 UI 中出现令人困惑的错误和不一致。
Its not a good idea to call setData in each loop.在每个循环中调用 setData 并不是一个好主意。 Populate an array and pass it to
setData
once loop is complete.一旦循环完成,填充一个数组并将其传递给
setData
。
const getDataFromFirebase = async () => {
let response = await firestore.collection('someDatabase').get();
let newData = [];
response.forEach(item => newData.push(item.data().name));
// now set the new data
setData(prevData=> ([...prevData, ...newData]));
// or you can use Array.concat
// setData(prevData=> (prevData.concat(newData)));
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.