Update state with Object using React Hooks

Viewed 73

I'm getting data from Firebase and want to update state:

const [allProfile, setAllProfile] = useState([]);
.....
const displayProfileList = async () => {
        try {

            await profile
                .get()
                .then(querySnapshot => {

                    querySnapshot.docs.map(doc => {
                        const documentId = doc.id;                        
                        const nProfile = { id: documentId, doc: doc.data()}                        
                        console.log(nProfile);//nProfile contains data
                    
                        setAllProfile([...allProfile, nProfile]);
                        console.log(allProfile); // is empty
                    }
                    );

                })
        } catch (error) {
            console.log('xxx', error);
        }
    }
3 Answers

Since setAllProfile is the asynchronous method, you can't get the updated value immediately after setAllProfile. You should get it inside useEffect with adding a allProfile dependency.

setAllProfile([...allProfile, nProfile]);
console.log(allProfile); // Old `allProfile` value will be printed, which is the initial empty array.
useEffect(() => {
  console.log(allProfile);
}, [allProfile]);

UPDATE

const [allProfile, setAllProfile] = useState([]);
.....
const displayProfileList = async () => {
        try {

            await profile
                .get()
                .then(querySnapshot => {
                    const profiles = [];

                    querySnapshot.docs.map(doc => {
                        const documentId = doc.id;                        
                        const nProfile = { id: documentId, doc: doc.data()}                        
                        console.log(nProfile);//nProfile contains data
                        profiles.push(nProfile);
                    
                    }
                    );
                    setAllProfile([...allProfile, ...profiles]);


                })
        } catch (error) {
            console.log('xxx', error);
        }
    }

The setAllProfile will update the state when the iteration is done. So in order for your code to work, you will need to pass the callback function to the setAllProfile as shown in the docs

setAllProfile((prevState) => [...prevState, nProfile])

UPDATE

Example demonstrating this at work

You are calling setState inside a map and therefore create few async calls, all referred to by current ..allProfile value call (and not prev => [...prev...)

Try

 let arr=[]
 querySnapshot.docs.map(doc => {
                  arr.push({ id: doc.id, doc: doc.data() })
            }                                 
 setAllProfile(prev=>[...prev,  ...arr])

I don't sure how the architecture of fetching the posts implemented (in terms of pagination and so on, so you might don't need to destruct ...prev

Related