Schema Cannot Read Property 'latitude' of Undefined
React - Cannot read property 'map' of undefined
March 12, 2020 - 5 min read
If you are a react developer, at that place is a adept run a risk that you lot 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 just want the bottom line, and then here information technology is
The trouble
In order to understand what are the possible solutions, lets first understand what is the exact issue hither.
Consider this code cake:
// Just a data fetching function const fetchURL = "https://jsonplaceholder.typicode.com/todos/" ; const getItems = ( ) => fetch (fetchURL) . and so ( res => res. json ( ) ) ; function App ( ) { const [items, setItems] = useState ( ) ; useEffect ( ( ) => { getItems ( ) . then ( data => setItems (data) ) ; } , [ ] ) ; render ( <div > {items. map ( item => ( <div key = {item.id} > {item.title} </div > ) ) } </div > ) ; }
We have a component that manage a state of items
, information technology also have an effect which inside it we run an asynchronous operation - getItems
, which volition return us the data
we need from the server, then we call setItems
with the received data as items
. This component also renders the items
- information technology iterate over information technology with .map
and returning a react element for each item.
Only we wont see anything on the screen, well except the error:
TypeError: Cannot read holding 'map' of undefined
What's going on here?
We practice have an items
variable:
const [items, setItems] = useState ( ) ;
And we did populate it with our data returned from the server:
useEffect ( ( ) => { getItems ( ) . then ( data => setItems (data) ) ; } , [ ] ) ;
Well lets examine how the react flow looks similar in our example:
- React renders (invoking) our component.
- React "run across" the
useState
call and render the states[undefined, fn]
. - React evaluate our return statement, when information technology hits the
items.map(...)
line its actually runningundefined.map(...)
which is manifestly an error in JavaScript.
What about our useEffect
call though?
React will run all furnishings afterward the render is committed to the screen, which means we tin't avoid a first render without our data.
Possible solutions
#1 Initial value
One possible solution is to requite your variable a default initial value, with useState
it would expect like that:
const [items, setItems] = useState ( [ ] ) ;
This means that when react runs our useState([])
telephone call, information technology will return u.s.a. with
Which means that in the first render of our component, react will "see" our items
every bit an empty array, 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
we have the items then return them, else
don't render (or render something else).
When working with JSX
we tin can't merely throw some if
else
statements within our tree:
// ⚠️ wont piece of work!! consign default office App ( ) { // .... return ( <div > { if (items) { items. map ( item => ( <div cardinal = {detail.id} > {item.championship} </div > ) ) } } </div > ) ; }
Merely instead we can create a variable exterior our tree and populate it conditionally:
Note that nosotros removed the initial array for items
.
part App ( ) { const [items, setItems] = useState ( ) ; useEffect ( ( ) => { getItems ( ) . then ( data => setItems (data) ) ; } , [ ] ) ; let itemsToRender; if (items) { itemsToRender = items. map ( item => { return <div key = {item.id} > {item.title} </div > ; } ) ; } return <div > {itemsToRender} </div > ; }
The undefined
or naught
values are ignored inside the context of JSX
so its safe to pass it on for the outset render.
Nosotros could also utilize an else
statement if we desire to render something else like a spinner or some text:
function App ( ) { const [items, setItems] = useState ( ) ; useEffect ( ( ) => { getItems ( ) . then ( data => setItems (data) ) ; } , [ ] ) ; allow itemsToRender; if (items) { itemsToRender = items. map ( item => { render <div key = {particular.id} > {particular.title} </div > ; } ) ; } else { itemsToRender = "Loading..." ; } return <div > {itemsToRender} </div > ; }
#ii.5 Inline conditional rendering
Another pick to conditionally render something in react, is to use the &&
logical operator:
part App ( ) { const [items, setItems] = useState ( ) ; useEffect ( ( ) => { getItems ( ) . then ( information => setItems (information) ) ; } , [ ] ) ; return ( <div > {items && items. map ( item => { return <div key = {particular.id} > {item.championship} </div > ; } ) } </div > ) ; }
Why information technology works? The react docs explains it well:
It works because in JavaScript, true && expression always evaluates to expression, and simulated && expression ever evaluates to false. Therefore, if the status is true, the element correct afterwards && will announced in the output. If it is false, React will ignore and skip it.
Nosotros tin can also use the provisional operator condition ? true : faux
if we want to render the Loading...
text:
role App ( ) { const [items, setItems] = useState ( ) ; useEffect ( ( ) => { getItems ( ) . then ( data => setItems (data) ) ; } , [ ] ) ; return ( <div > {items ? items. map ( item => { return <div central = {item.id} > {item.title} </div > ; } ) : "Loading..." } </div > ) ; }
We tin also mix both solutions, i.eastward: initial value with conditional rendering:
function App ( ) { const [items, setItems] = useState ( [ ] ) ; useEffect ( ( ) => { getItems ( ) . then ( data => setItems (data) ) ; } , [ ] ) ; render ( <div > {items && items.length > 0 ? items. map ( particular => { render <div key = {detail.id} > {detail.championship} </div > ; } ) : "Loading..." } </div > ) ; }
Though keep in listen, whenever atmospheric condition become too circuitous, information technology might exist a bespeak for us to excerpt that logic to a component:
role List ( { items, fallback } ) { if ( !items || items.length === 0 ) { render fallback; } else { return items. map ( item => { return <div key = {particular.id} > {item.title} </div > ; } ) ; } } function App ( ) { const [items, setItems] = useState ( [ ] ) ; useEffect ( ( ) => { getItems ( ) . then ( information => setItems (data) ) ; } , [ ] ) ; return ( <div > < List items = {items} fallback = { "Loading..." } /> </div > ) ; }
Wrapping up
When we get such an error, we are probably getting the value in an asynchronous way. We should provide an initial value for our variable or conditionally return it or both. If our condition get too complex, it might be a proficient time to excerpt the logic to a component.
Hope yous found this commodity helpful, if you have a different arroyo or any suggestions i would beloved to hear about them, you can tweet or DM me @sag1v. 🤓
Source: https://www.debuggr.io/react-map-of-undefined/
Post a Comment for "Schema Cannot Read Property 'latitude' of Undefined"