Typeerror: Cannot Read Property 'message' of Undefined
React - Cannot read belongings 'map' of undefined
March 12, 2020 - 5 min read
If you are a react developer, there is a skillful chance that yous faced this fault 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 lesser line, then here it is
The trouble
In lodge to empathise what are the possible solutions, lets offset understand what is the exact issue here.
Consider this code block:
// Only a data fetching function 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 (information) ) ; } , [ ] ) ; return ( <div > {items. map ( item => ( <div key = {particular.id} > {item.title} </div > ) ) } </div > ) ; } We have a component that manage a state of items, it besides have an consequence which inside it we run an asynchronous performance - getItems, which volition return us the data nosotros demand from the server, and then we call setItems with the received data as items. This component besides renders the items - it iterate over it with .map and returning a react chemical element for each item.
But we wont see anything on the screen, well except the fault:
TypeError: Cannot read property 'map' of undefined
What's going on here?
We do have an items variable:
const [items, setItems] = useState ( ) ; And we did populate information technology with our data returned from the server:
useEffect ( ( ) => { getItems ( ) . then ( data => setItems (data) ) ; } , [ ] ) ; Well lets examine how the react menstruum looks similar in our example:
- React renders (invoking) our component.
- React "run into" the
useStatecall and return us[undefined, fn]. - React evaluate our return statement, when information technology hits the
items.map(...)line its actually runningundefined.map(...)which is obviously an error in JavaScript.
What nigh our useEffect phone call though?
React will run all effects after the render is committed to the screen, which means we tin't avert a first render without our data.
Possible solutions
#1 Initial value
One possible solution is to give 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([]) phone call, information technology will return us with
Which ways that in the outset return of our component, react volition "encounter" our items equally an empty array, so instead of running undefined.map(...) similar before, it will run [].map(...).
#ii Provisional rendering
Another possible solution is to conditionally render the items, meaning if we have the items so render them, else don't render (or render something else).
When working with JSX we can't just throw some if else statements inside our tree:
// ⚠️ wont work!! export default role App ( ) { // .... return ( <div > { if (items) { items. map ( detail => ( <div key = {item.id} > {item.championship} </div > ) ) } } </div > ) ; } But instead we can create a variable outside our tree and populate it conditionally:
Notation that we removed the initial array for items.
function App ( ) { const [items, setItems] = useState ( ) ; useEffect ( ( ) => { getItems ( ) . and then ( data => setItems (data) ) ; } , [ ] ) ; let itemsToRender; if (items) { itemsToRender = items. map ( particular => { return <div central = {item.id} > {detail.title} </div > ; } ) ; } return <div > {itemsToRender} </div > ; } The undefined or null values are ignored within the context of JSX so its safe to laissez passer it on for the first render.
We could also utilise an else statement if we want to return something else like a spinner or some text:
function App ( ) { const [items, setItems] = useState ( ) ; useEffect ( ( ) => { getItems ( ) . and then ( data => setItems (data) ) ; } , [ ] ) ; let itemsToRender; if (items) { itemsToRender = items. map ( item => { return <div cardinal = {particular.id} > {item.title} </div > ; } ) ; } else { itemsToRender = "Loading..." ; } return <div > {itemsToRender} </div > ; } #2.5 Inline conditional rendering
Another pick to conditionally return something in react, is to use the && logical operator:
function App ( ) { const [items, setItems] = useState ( ) ; useEffect ( ( ) => { getItems ( ) . so ( data => setItems (data) ) ; } , [ ] ) ; return ( <div > {items && items. map ( detail => { return <div fundamental = {item.id} > {item.title} </div > ; } ) } </div > ) ; } Why information technology 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 faux. Therefore, if the status is true, the element right after && will appear in the output. If it is faux, React will ignore and skip it.
We can besides use the provisional operator status ? truthful : false if we want to render the Loading... text:
part App ( ) { const [items, setItems] = useState ( ) ; useEffect ( ( ) => { getItems ( ) . then ( data => setItems (data) ) ; } , [ ] ) ; render ( <div > {items ? items. map ( particular => { return <div fundamental = {item.id} > {detail.championship} </div > ; } ) : "Loading..." } </div > ) ; } We can also mix both solutions, i.e: initial value with provisional rendering:
role App ( ) { const [items, setItems] = useState ( [ ] ) ; useEffect ( ( ) => { getItems ( ) . then ( data => setItems (data) ) ; } , [ ] ) ; return ( <div > {items && items.length > 0 ? items. map ( item => { return <div key = {particular.id} > {item.title} </div > ; } ) : "Loading..." } </div > ) ; } Though keep in mind, whenever conditions become too complex, it might be a signal for us to extract that logic to a component:
function Listing ( { items, fallback } ) { if ( !items || items.length === 0 ) { return fallback; } else { render items. map ( item => { return <div key = {detail.id} > {item.championship} </div > ; } ) ; } } function App ( ) { const [items, setItems] = useState ( [ ] ) ; useEffect ( ( ) => { getItems ( ) . then ( data => setItems (data) ) ; } , [ ] ) ; render ( <div > < Listing items = {items} fallback = { "Loading..." } /> </div > ) ; } Wrapping up
When we get such an mistake, we 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, information technology might be a good fourth dimension to excerpt the logic to a component.
Promise y'all constitute this article helpful, if you accept a dissimilar approach or any suggestions i would love to hear about them, yous can tweet or DM me @sag1v. 🤓
friendtherinceple.blogspot.com
Source: https://www.debuggr.io/react-map-of-undefined/
0 Response to "Typeerror: Cannot Read Property 'message' of Undefined"
Post a Comment