简体   繁体   中英

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.

Use the callback in 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. 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:

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.

prevState is necessary here because you are working in an asynchronous function. In theory, it should work without it after using a solution with dataToAdd if you don't change the state anywhere else.

try this fire setState once but build the array before:

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.

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). Doing so will lead to confusing bugs and inconsistencies in the UI.

Its not a good idea to call setData in each loop. Populate an array and pass it to setData once loop is complete.

     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)));
     }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM