Cannot Read Property 'lift' of Undefined at Tapoperatorfunction
React - Cannot read property 'map' of undefined
March 12, 2020 - five min read
If you are a react programmer, 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 fashion for reading or you just want the bottom line, then here it is
The problem
In order to sympathise what are the possible solutions, lets outset understand what is the exact issue hither.
Consider this code block:
// Only a data fetching function const fetchURL = "https://jsonplaceholder.typicode.com/todos/" ; const getItems = ( ) => fetch (fetchURL) . so ( res => res. json ( ) ) ; function App ( ) { const [items, setItems] = useState ( ) ; useEffect ( ( ) => { getItems ( ) . then ( data => setItems (information) ) ; } , [ ] ) ; return ( <div > {items. map ( particular => ( <div cardinal = {item.id} > {item.title} </div > ) ) } </div > ) ; }
We have a component that manage a country of items
, it too have an consequence which inside it we run an asynchronous performance - getItems
, which volition return u.s.a. the data
we need from the server, then we call setItems
with the received data equally items
. This component also renders the items
- it iterate over it with .map
and returning a react element for each detail.
Merely we wont see anything on the screen, well except the error:
TypeError: Cannot read property 'map' of undefined
What's going on hither?
We practise accept 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 period looks like in our example:
- React renders (invoking) our component.
- React "encounter" the
useState
call and return united states of america[undefined, fn]
. - React evaluate our return statement, when it hits the
items.map(...)
line its actually runningundefined.map(...)
which is manifestly an mistake in JavaScript.
What about our useEffect
phone call though?
React will run all effects subsequently the return is committed to the screen, which means we can't avoid a first render without our information.
Possible solutions
#1 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, it will render us with
Which means that in the showtime 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 render 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 just throw some if
else
statements inside our tree:
// ⚠️ wont work!! export default part App ( ) { // .... render ( <div > { if (items) { items. map ( detail => ( <div key = {item.id} > {item.title} </div > ) ) } } </div > ) ; }
But instead we can create a variable exterior our tree and populate it conditionally:
Annotation that we removed the initial array for items
.
role App ( ) { const [items, setItems] = useState ( ) ; useEffect ( ( ) => { getItems ( ) . then ( data => setItems (data) ) ; } , [ ] ) ; let itemsToRender; if (items) { itemsToRender = items. map ( item => { return <div central = {item.id} > {item.title} </div > ; } ) ; } return <div > {itemsToRender} </div > ; }
The undefined
or nothing
values are ignored inside the context of JSX
so its safe to laissez passer it on for the first render.
We could likewise use an else
argument 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) ) ; } , [ ] ) ; let itemsToRender; if (items) { itemsToRender = items. map ( particular => { return <div fundamental = {particular.id} > {detail.title} </div > ; } ) ; } else { itemsToRender = "Loading..." ; } return <div > {itemsToRender} </div > ; }
#2.5 Inline conditional rendering
Some other pick to conditionally render something in react, is to use the &&
logical operator:
role App ( ) { const [items, setItems] = useState ( ) ; useEffect ( ( ) => { getItems ( ) . then ( data => setItems (data) ) ; } , [ ] ) ; render ( <div > {items && items. map ( detail => { return <div key = {item.id} > {item.title} </div > ; } ) } </div > ) ; }
Why information technology works? The react docs explains it well:
It works because in JavaScript, true && expression always evaluates to expression, and false && expression always evaluates to false. Therefore, if the condition is true, the chemical element right subsequently && volition appear in the output. If information technology is false, React volition ignore and skip it.
Nosotros can also use the conditional operator condition ? true : false
if we want to return the Loading...
text:
part App ( ) { const [items, setItems] = useState ( ) ; useEffect ( ( ) => { getItems ( ) . and so ( information => setItems (data) ) ; } , [ ] ) ; return ( <div > {items ? items. map ( detail => { return <div cardinal = {item.id} > {item.title} </div > ; } ) : "Loading..." } </div > ) ; }
We can as well mix both solutions, i.e: initial value with provisional rendering:
function App ( ) { const [items, setItems] = useState ( [ ] ) ; useEffect ( ( ) => { getItems ( ) . and so ( information => setItems (data) ) ; } , [ ] ) ; return ( <div > {items && items.length > 0 ? items. map ( item => { render <div central = {item.id} > {particular.title} </div > ; } ) : "Loading..." } </div > ) ; }
Though continue in listen, whenever conditions become too complex, it might be a signal for u.s. to extract that logic to a component:
function List ( { items, fallback } ) { if ( !items || items.length === 0 ) { render fallback; } else { render items. map ( item => { return <div key = {particular.id} > {item.title} </div > ; } ) ; } } part App ( ) { const [items, setItems] = useState ( [ ] ) ; useEffect ( ( ) => { getItems ( ) . then ( data => setItems (data) ) ; } , [ ] ) ; return ( <div > < List items = {items} fallback = { "Loading..." } /> </div > ) ; }
Wrapping upwardly
When nosotros become such an error, we 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 too circuitous, it might be a good time to extract the logic to a component.
Promise y'all establish this article helpful, if y'all have a different approach or any suggestions i would honey to hear well-nigh them, y'all tin can tweet or DM me @sag1v. 🤓
quirionunfinamess.blogspot.com
Source: https://www.debuggr.io/react-map-of-undefined/
0 Response to "Cannot Read Property 'lift' of Undefined at Tapoperatorfunction"
Post a Comment