Home > Mobile >  how do I update my state from an API call side Effect in React native?
how do I update my state from an API call side Effect in React native?

Time:01-09

I have a piece of code that gets Metadata of a list of files from Firebase storage using the useEffect hook. I however, struggle to update my state within this useEffect. I have used the async/await pattern to mitigate the asynchronous nature of setState without much success.

My snippet in pseudocode:

const [someData,setSomeData]=useState([])
const dataArray=[]

useFocusEffect(
    useCallback(()=>{
        async function getData(){
            const result=await listAll(storageRef);
            await result.items.map(async (itemRef)=>{
                const Metadata=await getMetadata(itemRef);
                await dataArray.push({'name':Metadata.name})
                await console.log(dataArray) //shows the array being populated on each iteration
            })
            await setSomeData(dataArray);
            await console.log(someData) // I'm expecting it to print an updated state, prints an empty array instead
            }
            getData()
        },[])
    )

I also cannot seem to access the state in the return part of my code:

return(
    {someData.map(({item})=>{
        return(
            <View><Text>{item.name}</Text><View>)})

outputs nothing as far as I can tell.

What am I missing in my approach?

Thanks in advance

CodePudding user response:

  • setSomeData() does not return a promise, thus cannot be awaited.
  • dataArray needs to be scoped inside getData()
  • getData closes around someData, so it will never get the updated value as that function call is referring to the previous value
  • it might be easier to use a react native compatible async data library

CodePudding user response:

dataArray is being re-initialized to [] every render, and then you are setting someData to dataArray, effectively setting someData to an empty array. I think if you wrap your async map in a Promise.all then you can have dataArray scoped to your getData function:

const fetchData = useCallback(() => {
  async function getData() {
    const result = await listAll(storageRef);
    const dataArray = await Promise.all(
      result.items.map(async (itemRef) => {
        const Metadata = await getMetadata(itemRef);
        console.log(Metadata);
        return { name: Metadata.name };
      })
    );
    console.log("dataArray:\n", dataArray);
    setSomeData(dataArray);
    // even if you await setSomeData, someData will be the the updated value. 
    /*  If you want to see someData changes do
      useEffect(()=>{
        console.log(someData)
      },[someData])
    */
  }
  getData();
}, []);
useFocusEffect(fetchData);

  • Related