React Uncaught (in Promise) Typeerror: Cannot Read Property 'error' of Undefined
React - Cannot read property 'map' of undefined
March 12, 2020 - 5 min read
If you are a react developer, there is a good chance that you faced this error couple of times:
TypeError: Cannot read property 'map' of undefined
TL;DR - If you are not in the mode for reading or you only want the bottom line, then here it is
The problem
In guild to empathize what are the possible solutions, lets first understand what is the exact issue here.
Consider this code block:
// Just a information fetching role const fetchURL = "https://jsonplaceholder.typicode.com/todos/" ; const getItems = ( ) => fetch (fetchURL) . and then ( res => res. json ( ) ) ; function App ( ) { const [items, setItems] = useState ( ) ; useEffect ( ( ) => { getItems ( ) . then ( data => setItems (data) ) ; } , [ ] ) ; render ( <div > {items. map ( detail => ( <div key = {item.id} > {item.title} </div > ) ) } </div > ) ; }
We have a component that manage a state of items
, it besides take an effect which within information technology we run an asynchronous performance - getItems
, which volition return u.s. the data
we demand from the server, then we phone call setItems
with the received data every bit items
. This component also renders the items
- information technology iterate over it with .map
and returning a react element for each item.
But nosotros wont run into annihilation on the screen, well except the fault:
TypeError: Cannot read belongings 'map' of undefined
What'south going on here?
Nosotros do have an items
variable:
const [items, setItems] = useState ( ) ;
And we did populate information technology with our data returned from the server:
useEffect ( ( ) => { getItems ( ) . so ( data => setItems (data) ) ; } , [ ] ) ;
Well lets examine how the react catamenia looks like in our example:
- React renders (invoking) our component.
- React "see" the
useState
call and return us[undefined, fn]
. - React evaluate our render statement, when information technology hits the
items.map(...)
line its actually runningundefined.map(...)
which is obviously an fault in JavaScript.
What nearly our useEffect
call though?
React will run all effects after the render is committed to the screen, which means we tin't avert a showtime render without our data.
Possible solutions
#1 Initial value
I possible solution is to requite your variable a default initial value, with useState
it would look like that:
const [items, setItems] = useState ( [ ] ) ;
This means that when react runs our useState([])
call, it will render us with
Which means that in the first return of our component, react will "see" our items
as an empty array, and so instead of running undefined.map(...)
like before, information technology will run [].map(...)
.
#2 Conditional rendering
Another possible solution is to conditionally render the items
, meaning if
nosotros take the items so render them, else
don't render (or render something else).
When working with JSX
we can't only throw some if
else
statements inside our tree:
// ⚠️ wont piece of work!! export default function App ( ) { // .... render ( <div > { if (items) { items. map ( item => ( <div key = {item.id} > {item.title} </div > ) ) } } </div > ) ; }
Merely instead we can create a variable outside our tree and populate it conditionally:
Annotation that we removed the initial assortment for items
.
function App ( ) { const [items, setItems] = useState ( ) ; useEffect ( ( ) => { getItems ( ) . and so ( data => setItems (data) ) ; } , [ ] ) ; let itemsToRender; if (items) { itemsToRender = items. map ( detail => { return <div cardinal = {detail.id} > {particular.title} </div > ; } ) ; } return <div > {itemsToRender} </div > ; }
The undefined
or null
values are ignored within the context of JSX
then its safety to laissez passer it on for the first return.
We could also utilize an else
argument if nosotros want to render something else like a spinner or some text:
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} > {particular.title} </div > ; } ) ; } else { itemsToRender = "Loading..." ; } render <div > {itemsToRender} </div > ; }
#2.v Inline conditional rendering
Another option to conditionally render something in react, is to use the &&
logical operator:
function App ( ) { const [items, setItems] = useState ( ) ; useEffect ( ( ) => { getItems ( ) . then ( data => setItems (data) ) ; } , [ ] ) ; render ( <div > {items && items. map ( item => { return <div primal = {item.id} > {item.championship} </div > ; } ) } </div > ) ; }
Why it works? The react docs explains information technology well:
It works because in JavaScript, true && expression always evaluates to expression, and fake && expression always evaluates to imitation. Therefore, if the condition is true, the element right afterwards && will announced in the output. If information technology is fake, React will ignore and skip it.
Nosotros can also apply the conditional operator status ? true : false
if we want to render the Loading...
text:
function App ( ) { const [items, setItems] = useState ( ) ; useEffect ( ( ) => { getItems ( ) . then ( information => setItems (data) ) ; } , [ ] ) ; render ( <div > {items ? items. map ( item => { render <div central = {item.id} > {particular.title} </div > ; } ) : "Loading..." } </div > ) ; }
We tin too mix both solutions, i.due east: initial value with conditional rendering:
function App ( ) { const [items, setItems] = useState ( [ ] ) ; useEffect ( ( ) => { getItems ( ) . so ( data => setItems (information) ) ; } , [ ] ) ; return ( <div > {items && items.length > 0 ? items. map ( item => { render <div fundamental = {particular.id} > {item.title} </div > ; } ) : "Loading..." } </div > ) ; }
Though proceed in mind, whenever conditions get too complex, information technology might be a signal for us to extract that logic to a component:
function List ( { items, fallback } ) { if ( !items || items.length === 0 ) { return fallback; } else { return items. map ( item => { return <div key = {item.id} > {item.championship} </div > ; } ) ; } } function App ( ) { const [items, setItems] = useState ( [ ] ) ; useEffect ( ( ) => { getItems ( ) . then ( data => setItems (data) ) ; } , [ ] ) ; return ( <div > < Listing items = {items} fallback = { "Loading..." } /> </div > ) ; }
Wrapping upwardly
When nosotros become such an mistake, nosotros are probably getting the value in an asynchronous fashion. We should provide an initial value for our variable or conditionally render it or both. If our status become too complex, it might exist a practiced fourth dimension to extract the logic to a component.
Hope you found this article helpful, if you lot have a dissimilar approach or any suggestions i would honey to hear about them, you lot tin tweet or DM me @sag1v. 🤓
Source: https://www.debuggr.io/react-map-of-undefined/
0 Response to "React Uncaught (in Promise) Typeerror: Cannot Read Property 'error' of Undefined"
Post a Comment