Unhandled Rejection (Typeerror): Cannot Read Property 'map' of Undefined

React - Cannot read belongings 'map' of undefined

March 12, 2020 - 5 min read

If you are a react developer, in that location is a practiced chance that y'all faced this error couple of times:

TypeError: Cannot read property 'map' of undefined

TL;DR - If yous are non in the mode for reading or yous just want the bottom line, and then here information technology is

The problem

In lodge to understand what are the possible solutions, lets first sympathise what is the exact result here.

Consider this code block:

                          // Just a data fetching part              const              fetchURL              =              "https://jsonplaceholder.typicode.com/todos/"              ;              const              getItems              =              (              )              =>              fetch              (fetchURL)              .              so              (              res              =>              res.              json              (              )              )              ;              function              App              (              )              {              const              [items,              setItems]              =              useState              (              )              ;              useEffect              (              (              )              =>              {              getItems              (              )              .              and then              (              information              =>              setItems              (data)              )              ;              }              ,              [              ]              )              ;              return              (                                                <div                >                                                        {items.              map              (              particular              =>              (                                                <div                key                                  =                  {item.id}                                >                            {item.title}                                                </div                >                            )              )              }                                                                            </div                >                            )              ;              }                      

We have a component that manage a land of items, information technology also have an consequence which inside it we run an asynchronous operation - getItems, which will return u.s.a. the data we demand from the server, then we call setItems with the received data every bit items. This component also renders the items - it iterate over it with .map and returning a react chemical element for each item.

Simply we wont come across anything on the screen, well except the error:

TypeError: Cannot read property 'map' of undefined

What'southward 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                (information)                )                ;                            }              ,              [              ]              )              ;                      

Well lets examine how the react flow looks like in our example:

  1. React renders (invoking) our component.
  2. React "see" the useState call and return us [undefined, fn].
  3. React evaluate our render statement, when it hits the items.map(...) line its actually running undefined.map(...) which is obviously an fault in JavaScript.

What well-nigh our useEffect call though?

React will run all furnishings after the return is committed to the screen, which means we can't avoid a first return without our data.

Possible solutions

#one Initial value

One possible solution is to give your variable a default initial value, with useState it would wait like that:

                          const              [items,              setItems]              =              useState              (              [              ]              )              ;                      

This means that when react runs our useState([]) call, it will return us with

Which ways that in the first return of our component, react will "run into" our items every bit an empty assortment, so instead of running undefined.map(...) like before, it will run [].map(...).

#2 Provisional rendering

Some other 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 nosotros can't just throw some if else statements inside our tree:

                          // ⚠️ wont work!!              export              default              function              App              (              )              {              // ....              return              (                                                <div                >                                                                      {                              if                (items)                {                                            items.                map                (                item                =>                (                                                                                  <div                  key                                      =                    {particular.id}                                    >                                {item.title}                                                      </div                  >                                                            )                )                                            }                            }                                                                                          </div                >                            )              ;              }                      

Merely instead nosotros can create a variable outside our tree and populate it conditionally:

Note that we removed the initial array for items.

                          function              App              (              )              {              const              [items,              setItems]              =              useState              (              )              ;              useEffect              (              (              )              =>              {              getItems              (              )              .              then              (              data              =>              setItems              (data)              )              ;              }              ,              [              ]              )              ;                              let                itemsToRender;                                            if                (items)                {                                            itemsToRender                =                items.                map                (                detail                =>                {                                            return                                                      <div                  central                                      =                    {item.id}                                    >                                {item.title}                                                      </div                  >                                ;                                            }                )                ;                                            }                                            return                                                      <div                  >                                {itemsToRender}                                                      </div                  >                                ;                            }                      

The undefined or null values are ignored inside the context of JSX so its prophylactic to laissez passer it on for the first return.

We could besides utilise an else statement if nosotros desire to render 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                key                                  =                  {item.id}                                >                            {particular.championship}                                                </div                >                            ;              }              )              ;                              }                else                {                                            itemsToRender                =                "Loading..."                ;                                            }                            return                                                <div                >                            {itemsToRender}                                                </div                >                            ;              }                      

#2.5 Inline provisional rendering

Another option to conditionally render something in react, is to apply the && logical operator:

                          function              App              (              )              {              const              [items,              setItems]              =              useState              (              )              ;              useEffect              (              (              )              =>              {              getItems              (              )              .              then              (              information              =>              setItems              (data)              )              ;              }              ,              [              ]              )              ;              return              (                                                <div                >                                                                                          {items                &&                items.                map                (                particular                =>                {                                            return                                                      <div                  key                                      =                    {item.id}                                    >                                {particular.title}                                                      </div                  >                                ;                                            }                )                }                                                                                                          </div                >                            )              ;              }                      

Why information technology works? The react docs explains it well:

It works because in JavaScript, truthful && expression e'er evaluates to expression, and simulated && expression always evaluates to imitation. Therefore, if the condition is true, the element correct after && will announced in the output. If it is false, React will ignore and skip it.

We can also use the conditional operator condition ? true : false if nosotros desire to render the Loading... text:

                          function              App              (              )              {              const              [items,              setItems]              =              useState              (              )              ;              useEffect              (              (              )              =>              {              getItems              (              )              .              then              (              data              =>              setItems              (data)              )              ;              }              ,              [              ]              )              ;              return              (                                                <div                >                                                                                          {items                              ?                items.                map                (                item                =>                {                                            render                                                      <div                  cardinal                                      =                    {detail.id}                                    >                                {particular.title}                                                      </div                  >                                ;                                            }                )                                            :                "Loading..."                }                                                                                                          </div                >                            )              ;              }                      

We can also mix both solutions, i.e: initial value with conditional rendering:

                          function              App              (              )              {                              const                [items,                setItems]                =                useState                (                [                ]                )                ;                            useEffect              (              (              )              =>              {              getItems              (              )              .              and then              (              data              =>              setItems              (data)              )              ;              }              ,              [              ]              )              ;              render              (                                                <div                >                                                                                          {items                &&                items.length                >                0                                            ?                items.                map                (                detail                =>                {                                            render                                                      <div                  central                                      =                    {particular.id}                                    >                                {item.title}                                                      </div                  >                                ;                                            }                )                                            :                "Loading..."                }                                                                                                          </div                >                            )              ;              }                      

Though proceed in mind, whenever conditions become too complex, it might be a signal for us to extract that logic to a component:

                                          function                List                (                                  {                  items,                  fallback                  }                                )                {                                            if                (                !items                ||                items.length                ===                0                )                {                                            return                fallback;                                            }                else                {                                            return                items.                map                (                item                =>                {                                            return                                                      <div                  cardinal                                      =                    {item.id}                                    >                                {item.title}                                                      </div                  >                                ;                                            }                )                ;                                            }                                            }                            function              App              (              )              {              const              [items,              setItems]              =              useState              (              [              ]              )              ;              useEffect              (              (              )              =>              {              getItems              (              )              .              and so              (              data              =>              setItems              (data)              )              ;              }              ,              [              ]              )              ;              return              (                                                <div                >                                                                                                                                <                    List                                    items                                      =                    {items}                                    fallback                                      =                    {                    "Loading..."                    }                                    />                                                                                                                          </div                >                            )              ;              }                      

Wrapping up

When nosotros become such an error, we are probably getting the value in an asynchronous way. Nosotros should provide an initial value for our variable or conditionally return it or both. If our condition get besides complex, it might be a good time to excerpt the logic to a component.

Hope you found this article helpful, if you lot have a different approach or any suggestions i would dear to hear about them, you can tweet or DM me @sag1v. 🤓

readysuccionoth56.blogspot.com

Source: https://www.debuggr.io/react-map-of-undefined/

0 Response to "Unhandled Rejection (Typeerror): Cannot Read Property 'map' of Undefined"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel