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
.