Cannot Read Property Function of Undefined Sinon
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 y'all faced this fault couple of times:
TypeError: Cannot read holding 'map' of undefined
TL;DR - If y'all are non in the style for reading or you but want the bottom line, so here information technology is
The problem
In order to understand what are the possible solutions, lets first empathize what is the exact issue hither.
Consider this lawmaking block:
// Just a information 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 (information) ) ; } , [ ] ) ; return ( <div > {items. map ( item => ( <div fundamental = {item.id} > {item.championship} </div > ) ) } </div > ) ; }
We have a component that manage a state of items
, information technology also take an effect which inside information technology we run an asynchronous operation - getItems
, which will render us the data
nosotros 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 item.
But nosotros wont see annihilation on the screen, well except the fault:
TypeError: Cannot read holding 'map' of undefined
What's going on here?
Nosotros do have an items
variable:
const [items, setItems] = useState ( ) ;
And we did populate it with our information returned from the server:
useEffect ( ( ) => { getItems ( ) . and then ( information => setItems (data) ) ; } , [ ] ) ;
Well lets examine how the react catamenia looks like in our example:
- React renders (invoking) our component.
- React "run into" the
useState
call and return us[undefined, fn]
. - React evaluate our return statement, when it hits the
items.map(...)
line its actually runningundefined.map(...)
which is obviously an error in JavaScript.
What almost our useEffect
call though?
React will run all effects after the render is committed to the screen, which ways we can't avert a showtime render without our data.
Possible solutions
#ane 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([])
call, it will return u.s. with
Which means that in the kickoff render of our component, react will "see" our items
every bit an empty array, so instead of running undefined.map(...)
like earlier, information technology will run [].map(...)
.
#2 Provisional rendering
Another possible solution is to conditionally render the items
, meaning if
we accept the items then render them, else
don't render (or render something else).
When working with JSX
nosotros can't just throw some if
else
statements inside our tree:
// ⚠️ wont work!! export default function App ( ) { // .... return ( <div > { if (items) { items. map ( detail => ( <div key = {item.id} > {particular.title} </div > ) ) } } </div > ) ; }
But instead we can create a variable outside our tree and populate it conditionally:
Note that we removed the initial array for items
.
office App ( ) { const [items, setItems] = useState ( ) ; useEffect ( ( ) => { getItems ( ) . and then ( data => setItems (data) ) ; } , [ ] ) ; permit itemsToRender; if (items) { itemsToRender = items. map ( item => { return <div fundamental = {item.id} > {item.title} </div > ; } ) ; } return <div > {itemsToRender} </div > ; }
The undefined
or nothing
values are ignored inside the context of JSX
then its safe to pass it on for the get-go render.
We could also use an else
argument if we want to render something else like a spinner or some text:
part App ( ) { const [items, setItems] = useState ( ) ; useEffect ( ( ) => { getItems ( ) . and then ( data => setItems (information) ) ; } , [ ] ) ; let itemsToRender; if (items) { itemsToRender = items. map ( item => { return <div primal = {item.id} > {item.championship} </div > ; } ) ; } else { itemsToRender = "Loading..." ; } return <div > {itemsToRender} </div > ; }
#2.5 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 central = {item.id} > {item.title} </div > ; } ) } </div > ) ; }
Why information technology works? The react docs explains information technology well:
Information technology works because in JavaScript, true && expression always evaluates to expression, and false && expression always evaluates to simulated. Therefore, if the status is true, the element right afterwards && volition appear in the output. If it is false, React will ignore and skip it.
We tin can also apply the conditional operator condition ? true : false
if we want to render the Loading...
text:
role App ( ) { const [items, setItems] = useState ( ) ; useEffect ( ( ) => { getItems ( ) . and then ( data => setItems (data) ) ; } , [ ] ) ; return ( <div > {items ? items. map ( item => { return <div fundamental = {item.id} > {particular.title} </div > ; } ) : "Loading..." } </div > ) ; }
We can also mix both solutions, i.e: initial value with conditional rendering:
role App ( ) { const [items, setItems] = useState ( [ ] ) ; useEffect ( ( ) => { getItems ( ) . and so ( data => setItems (data) ) ; } , [ ] ) ; render ( <div > {items && items.length > 0 ? items. map ( item => { return <div primal = {particular.id} > {item.championship} </div > ; } ) : "Loading..." } </div > ) ; }
Though keep in mind, whenever weather become too complex, it might exist a point for united states of america to extract that logic to a component:
part List ( { items, fallback } ) { if ( !items || items.length === 0 ) { return fallback; } else { render items. map ( particular => { return <div key = {item.id} > {item.title} </div > ; } ) ; } } office App ( ) { const [items, setItems] = useState ( [ ] ) ; useEffect ( ( ) => { getItems ( ) . and so ( data => setItems (information) ) ; } , [ ] ) ; return ( <div > < List items = {items} fallback = { "Loading..." } /> </div > ) ; }
Wrapping up
When we go such an fault, 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 status become too complex, it might exist a good time to extract the logic to a component.
Hope you plant this article helpful, if you have a different approach or any suggestions i would love to hear near them, you can tweet or DM me @sag1v. 🤓
Source: https://www.debuggr.io/react-map-of-undefined/
0 Response to "Cannot Read Property Function of Undefined Sinon"
Post a Comment