Spread operator with React useState // Populating state from Firebase

I’m retrieving some data from Firebase that returns two objects which I want to store as an array in local state. I’m trying to use the spread opperator to maintain the current state and append new records but it seems to keep overwriting the original?

Code below returns two objects from firebase but I’m only able to see the last object set in state.

const [date, setDate] = useState(new Date(new Date().setHours(0, 0, 0, 0))); //setting initial state to current day midnight
    const [step, setStep] = useState(0); // Count the days ahead the user is trying to book.
    const [alert, setAlert] = useState(false); // Alert when trying to exceed booking window.
    const [bookings, setBookings] = useState([]);

    const bookingWindowAllowed = 7; // Used to limit the forward bookings (evaluated vs state.step)

    useEffect(() => {
        setLoading(true);
        setBookings([]);

        //date as firestore timestamp
        const setDate = firebase.firestore.Timestamp.fromMillis(
            dayjs(date).valueOf()
        );
        //Compute tomorrow as firestore timestamp
        const futureDate = firebase.firestore.Timestamp.fromMillis(
            dayjs(date).add(1, 'day').valueOf()
        );

        // Get bookings from firestore
        firestore
            .collection('bookings')
            .where('studio.ID', '==', 'kM8p1jSenI4M0Mr1PzBo')
            .where('startTime', '>=', setDate)
            .where('startTime', '<', futureDate)
            .get()
            .then((querySnapshot) => {
                querySnapshot.forEach((doc) => {
                    console.log(doc.data());
                    setBookings([...bookings, doc.data()]);
                });
                setLoading(false);
            })
            .catch((error) => {
                console.log('Error getting documents: ', error);
                setLoading(false);
            });
    }, [date]);

Answer

React setState functions are asynchronous, meaning they don’t change the state right away, that is why patterns like the one you are implementing don’t work as expected.

Better to save those two objects in an array, after the iteration, save that array in state:

useEffect(() => {
    setLoading(true);
    setBookings([]);

    //date as firestore timestamp
    const setDate = firebase.firestore.Timestamp.fromMillis(
        dayjs(date).valueOf()
    );
    //Compute tomorrow as firestore timestamp
    const futureDate = firebase.firestore.Timestamp.fromMillis(
        dayjs(date).add(1, 'day').valueOf()
    );
    // Get bookings from firestore
    firestore
        .collection('bookings')
        .where('studio.ID', '==', 'kM8p1jSenI4M0Mr1PzBo')
        .where('startTime', '>=', setDate)
        .where('startTime', '<', futureDate)
        .get()
        .then((querySnapshot) => {

            const newBookings=[]    /// create an empty array

            querySnapshot.forEach((doc) => {
                console.log(doc.data());
                newBookings.push(doc.data()); // push each object to newBookings
            });
            setBookings(newBookings); // save it in state
            setLoading(false);
        })
        .catch((error) => {
            console.log('Error getting documents: ', error);
            setLoading(false);
        });
}, [date]);