Skip to content
Advertisement

Spread objects into a state array

I am trying to spread values as objects into a state array in react, but this code causes this error:

Error:

TypeError: Invalid attempt to spread non-iterable instance. In order to be iterable, non-array objects must have a [Symbol.iterator]() method.

Is there a chance I can spread values from the data array into a values state array as objects, so values array would be the same as the data array?

import { useState } from "react";
import "./styles.css";

export default function App() {
  const [places, setPlaces] = useState([]);
    const [isLoaded, setIsLoaded] = useState(false);

    useEffect(() => {
        const getData = async () => {
            const q = query(collection(firestore, 'places'));

            await getDocs(q)
                .then((data) => {
                    data.forEach((item) => {
                        if (item.exists()) {
                            setPlaces((prevState) => [...prevState, ...item.data()]);
                        }
                    });
                });

            setIsLoaded(true);
        };

        getData();
    }, []);
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
    </div>
  );
}

Advertisement

Answer

It sounds like item.data() doesn’t return an iterable.

There’s no need for that forEach, just use the data directly. If you need to map it (sounds like you do, calling item.data() on each item), you can use map for that:

useEffect(() => {
    const getData = async () => {
        const q = query(collection(firestore, "<collectionName>"));

        const data = await getDocs(q);
        setPlaces((prevPlaces) => [
            ...prevPlaces,
            ...data.map((item) => item.data()),
        ]);
        setIsLoaded(true);
    };

    getData();
}, []);

That spreads the new array from map, it doesn’t try to spread item.data().


In a comment you’ve said that using data.map(/*...*/) causes:

data.map is not a function

That means data isn’t an array as the question states, it’s some other kind of collection with a forEach method.

If it’s an array-like¹ or an iterable, you can do the mapping with Array.from:

setPlaces((prevPlaces) => [
    ...prevPlaces,
    ...Array.from(data, (item) => item.data()), // ***
]);

If it’s not an array-like or iterable, then worst case, you can use forEach to create a new array:

const mapped = [];
data.forEach((item) => mapped.push(item.data()));
setPlaces((prevPlaces) => [
    ...prevPlaces,
    ...mapped
]);

¹ “array-like” – Has a length property and has properties for its elements with names that are the indexes 0 through length - 1.

User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement