Typeerror Cannot Read Property 'navigate' of Undefined React Native
React - Cannot read property 'map' of undefined
March 12, 2020 - five min read
If you are a react developer, there is a expert risk that you faced this error couple of times:
TypeError: Cannot read holding 'map' of undefined
TL;DR - If you lot are not in the mode for reading or yous just want the bottom line, and then here it is
The problem
In social club to empathise what are the possible solutions, lets first understand what is the exact consequence here.
Consider this code block:
// Just 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 ( data => setItems (data) ) ; } , [ ] ) ; return ( <div > {items. map ( item => ( <div key = {particular.id} > {item.title} </div > ) ) } </div > ) ; }
We have a component that manage a state of items
, information technology as well accept an result which inside it we run an asynchronous performance - getItems
, which will return the states the data
we demand from the server, then we call setItems
with the received data as items
. This component also renders the items
- it iterate over information technology with .map
and returning a react chemical element for each item.
Merely we wont see annihilation on the screen, well except the error:
TypeError: Cannot read holding 'map' of undefined
What'due south going on here?
We practice have an items
variable:
const [items, setItems] = useState ( ) ;
And nosotros did populate it with our information returned from the server:
useEffect ( ( ) => { getItems ( ) . so ( data => setItems (information) ) ; } , [ ] ) ;
Well lets examine how the react catamenia looks like in our example:
- React renders (invoking) our component.
- React "see" the
useState
telephone call and return us[undefined, fn]
. - React evaluate our return statement, when it hits the
items.map(...)
line its really runningundefined.map(...)
which is obviously an error in JavaScript.
What about our useEffect
call though?
React will run all effects afterward the return is committed to the screen, which means nosotros can't avert a get-go render without our data.
Possible solutions
#1 Initial value
Ane possible solution is to requite your variable a default initial value, with useState
it would look like that:
const [items, setItems] = useState ( [ ] ) ;
This ways that when react runs our useState([])
telephone call, information technology will return us with
Which means that in the first return of our component, react volition "see" our items
every bit an empty array, so instead of running undefined.map(...)
like before, it volition run [].map(...)
.
#2 Conditional rendering
Another possible solution is to conditionally return the items
, pregnant if
nosotros have the items and then render them, else
don't render (or render something else).
When working with JSX
we tin can't but throw some if
else
statements inside our tree:
// ⚠️ wont work!! export default function App ( ) { // .... return ( <div > { if (items) { items. map ( item => ( <div key = {item.id} > {particular.title} </div > ) ) } } </div > ) ; }
But instead nosotros 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 ( information => setItems (information) ) ; } , [ ] ) ; let itemsToRender; if (items) { itemsToRender = items. map ( item => { return <div cardinal = {particular.id} > {item.title} </div > ; } ) ; } render <div > {itemsToRender} </div > ; }
The undefined
or cypher
values are ignored inside the context of JSX
so its condom to laissez passer it on for the starting time return.
We could also use 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 so ( information => setItems (data) ) ; } , [ ] ) ; let itemsToRender; if (items) { itemsToRender = items. map ( detail => { return <div cardinal = {item.id} > {item.championship} </div > ; } ) ; } else { itemsToRender = "Loading..." ; } render <div > {itemsToRender} </div > ; }
#2.5 Inline conditional rendering
Another choice to conditionally render something in react, is to use the &&
logical operator:
part App ( ) { const [items, setItems] = useState ( ) ; useEffect ( ( ) => { getItems ( ) . then ( data => setItems (data) ) ; } , [ ] ) ; return ( <div > {items && items. map ( particular => { return <div cardinal = {item.id} > {item.title} </div > ; } ) } </div > ) ; }
Why information technology works? The react docs explains it well:
It works considering in JavaScript, true && expression e'er evaluates to expression, and simulated && expression always evaluates to false. Therefore, if the status is true, the element correct after && will appear in the output. If information technology is false, React will ignore and skip it.
We tin can also use the conditional operator condition ? true : false
if nosotros want to render the Loading...
text:
function App ( ) { const [items, setItems] = useState ( ) ; useEffect ( ( ) => { getItems ( ) . and so ( data => setItems (data) ) ; } , [ ] ) ; return ( <div > {items ? items. map ( particular => { return <div central = {particular.id} > {item.title} </div > ; } ) : "Loading..." } </div > ) ; }
Nosotros can also mix both solutions, i.east: initial value with conditional rendering:
function App ( ) { const [items, setItems] = useState ( [ ] ) ; useEffect ( ( ) => { getItems ( ) . then ( data => setItems (information) ) ; } , [ ] ) ; return ( <div > {items && items.length > 0 ? items. map ( item => { return <div key = {particular.id} > {item.title} </div > ; } ) : "Loading..." } </div > ) ; }
Though keep in heed, whenever weather condition become too complex, it might be a bespeak for us to extract that logic to a component:
function Listing ( { items, fallback } ) { if ( !items || items.length === 0 ) { return fallback; } else { return items. map ( item => { return <div key = {particular.id} > {detail.title} </div > ; } ) ; } } office App ( ) { const [items, setItems] = useState ( [ ] ) ; useEffect ( ( ) => { getItems ( ) . and so ( data => setItems (data) ) ; } , [ ] ) ; return ( <div > < List items = {items} fallback = { "Loading..." } /> </div > ) ; }
Wrapping up
When nosotros get such an error, 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 go too complex, information technology might be a good time to extract the logic to a component.
Hope you lot establish this article helpful, if you have a dissimilar approach or whatever suggestions i would dearest to hear about them, y'all can tweet or DM me @sag1v. 🤓
Source: https://www.debuggr.io/react-map-of-undefined/
0 Response to "Typeerror Cannot Read Property 'navigate' of Undefined React Native"
Post a Comment