Typeerror Cannot Read Property 'map' of Undefined Jest React
React - Cannot read property 'map' of undefined
March 12, 2020 - 5 min read
If you are a react programmer, in that location is a good take chances that yous faced this mistake couple of times:
TypeError: Cannot read property 'map' of undefined
TL;DR - If you are not in the mode for reading or you simply want the bottom line, then hither information technology is
The trouble
In order to understand what are the possible solutions, lets first sympathize what is the exact issue hither.
Consider this lawmaking block:
// Just a data fetching part const fetchURL = "https://jsonplaceholder.typicode.com/todos/" ; const getItems = ( ) => fetch (fetchURL) . then ( res => res. json ( ) ) ; function App ( ) { const [items, setItems] = useState ( ) ; useEffect ( ( ) => { getItems ( ) . then ( information => setItems (data) ) ; } , [ ] ) ; return ( <div > {items. map ( particular => ( <div primal = {item.id} > {item.title} </div > ) ) } </div > ) ; }
We have a component that manage a state of items
, it too have an effect which inside it we run an asynchronous performance - getItems
, which volition return us the data
we need from the server, and then we telephone call setItems
with the received data as items
. This component also renders the items
- it iterate over it with .map
and returning a react element for each item.
Just we wont see anything on the screen, well except the mistake:
TypeError: Cannot read property 'map' of undefined
What'southward going on hither?
Nosotros do take an items
variable:
const [items, setItems] = useState ( ) ;
And we did populate it with our information returned from the server:
useEffect ( ( ) => { getItems ( ) . and so ( information => setItems (information) ) ; } , [ ] ) ;
Well lets examine how the react period looks like in our example:
- React renders (invoking) our component.
- React "see" the
useState
phone call and return us[undefined, fn]
. - React evaluate our render statement, when information technology hits the
items.map(...)
line its really runningundefined.map(...)
which is patently an error in JavaScript.
What about our useEffect
telephone call though?
React will run all effects after the render is committed to the screen, which ways we can't avoid a showtime render without our data.
Possible solutions
#ane Initial value
One possible solution is to give your variable a default initial value, with useState
information technology would look like that:
const [items, setItems] = useState ( [ ] ) ;
This means that when react runs our useState([])
call, information technology will return us with
Which means that in the first render of our component, react will "see" our items
as an empty array, so instead of running undefined.map(...)
like before, it will run [].map(...)
.
#2 Conditional rendering
Another possible solution is to conditionally return the items
, meaning if
we have the items then render them, else
don't render (or render something else).
When working with JSX
we can't merely throw some if
else
statements within our tree:
// ⚠️ wont piece of work!! consign default role App ( ) { // .... return ( <div > { if (items) { items. map ( particular => ( <div key = {detail.id} > {item.championship} </div > ) ) } } </div > ) ; }
But instead we tin create a variable outside our tree and populate it conditionally:
Annotation that we removed the initial array for items
.
function App ( ) { const [items, setItems] = useState ( ) ; useEffect ( ( ) => { getItems ( ) . then ( data => setItems (data) ) ; } , [ ] ) ; let itemsToRender; if (items) { itemsToRender = items. map ( item => { return <div key = {item.id} > {detail.championship} </div > ; } ) ; } render <div > {itemsToRender} </div > ; }
The undefined
or null
values are ignored inside the context of JSX
so its prophylactic to pass it on for the outset return.
We could as well use an else
statement if we desire to return something else similar a spinner or some text:
function App ( ) { const [items, setItems] = useState ( ) ; useEffect ( ( ) => { getItems ( ) . then ( data => setItems (information) ) ; } , [ ] ) ; let itemsToRender; if (items) { itemsToRender = items. map ( particular => { return <div central = {item.id} > {detail.title} </div > ; } ) ; } else { itemsToRender = "Loading..." ; } return <div > {itemsToRender} </div > ; }
#2.5 Inline conditional rendering
Another pick to conditionally render something in react, is to apply the &&
logical operator:
function App ( ) { const [items, setItems] = useState ( ) ; useEffect ( ( ) => { getItems ( ) . then ( data => setItems (information) ) ; } , [ ] ) ; return ( <div > {items && items. map ( item => { return <div key = {item.id} > {item.championship} </div > ; } ) } </div > ) ; }
Why it works? The react docs explains it well:
It works because in JavaScript, true && expression e'er evaluates to expression, and imitation && expression always evaluates to fake. Therefore, if the condition is true, the element correct after && volition announced in the output. If it is faux, React will ignore and skip it.
Nosotros tin also utilise the conditional operator condition ? true : imitation
if we want to render the Loading...
text:
function App ( ) { const [items, setItems] = useState ( ) ; useEffect ( ( ) => { getItems ( ) . then ( information => setItems (data) ) ; } , [ ] ) ; return ( <div > {items ? items. map ( particular => { render <div key = {item.id} > {item.title} </div > ; } ) : "Loading..." } </div > ) ; }
We can also mix both solutions, i.due east: initial value with conditional rendering:
role App ( ) { const [items, setItems] = useState ( [ ] ) ; useEffect ( ( ) => { getItems ( ) . and then ( information => setItems (data) ) ; } , [ ] ) ; return ( <div > {items && items.length > 0 ? items. map ( item => { render <div key = {item.id} > {item.championship} </div > ; } ) : "Loading..." } </div > ) ; }
Though keep in mind, whenever conditions become besides complex, it might be a signal for the states to extract that logic to a component:
part Listing ( { items, fallback } ) { if ( !items || items.length === 0 ) { return fallback; } else { return items. map ( item => { render <div key = {particular.id} > {item.title} </div > ; } ) ; } } part App ( ) { const [items, setItems] = useState ( [ ] ) ; useEffect ( ( ) => { getItems ( ) . then ( data => setItems (information) ) ; } , [ ] ) ; return ( <div > < Listing items = {items} fallback = { "Loading..." } /> </div > ) ; }
Wrapping up
When nosotros get such an fault, nosotros are probably getting the value in an asynchronous way. We should provide an initial value for our variable or conditionally render it or both. If our condition get as well circuitous, it might be a expert time to excerpt the logic to a component.
Hope y'all found this commodity helpful, if you accept a dissimilar approach or whatever suggestions i would dearest to hear nigh them, you lot can tweet or DM me @sag1v. 🤓
phillipsristraid1999.blogspot.com
Source: https://www.debuggr.io/react-map-of-undefined/
0 Response to "Typeerror Cannot Read Property 'map' of Undefined Jest React"
Post a Comment