React Uncaught (in Promise) Typeerror: Cannot Read Property 'error' of Undefined

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 you faced this error couple of times:

TypeError: Cannot read property 'map' of undefined

TL;DR - If you are not in the mode for reading or you only want the bottom line, then here it is

The problem

In guild to empathize what are the possible solutions, lets first understand what is the exact issue here.

Consider this code block:

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

We have a component that manage a state of items, it besides take an effect which within information technology we run an asynchronous performance - getItems, which volition return u.s. the data we demand from the server, then we phone call setItems with the received data every bit items. This component also renders the items - information technology iterate over it with .map and returning a react element for each item.

But nosotros wont run into annihilation on the screen, well except the fault:

TypeError: Cannot read belongings 'map' of undefined

What'south going on here?

Nosotros do have an items variable:

                          const              [items,              setItems]              =              useState              (              )              ;                      

And we did populate information technology with our data returned from the server:

                          useEffect              (              (              )              =>              {                              getItems                (                )                .                so                (                data                =>                setItems                (data)                )                ;                            }              ,              [              ]              )              ;                      

Well lets examine how the react catamenia 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 information technology hits the items.map(...) line its actually running undefined.map(...) which is obviously an fault in JavaScript.

What nearly our useEffect call though?

React will run all effects after the render is committed to the screen, which means we tin't avert a showtime render without our data.

Possible solutions

#1 Initial value

I possible solution is to requite 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([]) call, it will render us with

Which means that in the first return of our component, react will "see" our items as an empty array, and so instead of running undefined.map(...) like before, information technology will run [].map(...).

#2 Conditional rendering

Another possible solution is to conditionally render the items, meaning if nosotros take the items so render them, else don't render (or render something else).

When working with JSX we can't only throw some if else statements inside our tree:

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

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

Annotation that we removed the initial assortment for items.

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

The undefined or null values are ignored within the context of JSX then its safety to laissez passer it on for the first return.

We could also utilize an else argument if nosotros want 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              (              item              =>              {              return                                                <div                key                                  =                  {item.id}                                >                            {particular.title}                                                </div                >                            ;              }              )              ;                              }                else                {                                            itemsToRender                =                "Loading..."                ;                                            }                            render                                                <div                >                            {itemsToRender}                                                </div                >                            ;              }                      

#2.v 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                  primal                                      =                    {item.id}                                    >                                {item.championship}                                                      </div                  >                                ;                                            }                )                }                                                                                                          </div                >                            )              ;              }                      

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

It works because in JavaScript, true && expression always evaluates to expression, and fake && expression always evaluates to imitation. Therefore, if the condition is true, the element right afterwards && will announced in the output. If information technology is fake, React will ignore and skip it.

Nosotros can also apply the conditional operator status ? true : false if we want to render the Loading... text:

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

We tin too mix both solutions, i.due east: initial value with conditional rendering:

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

Though proceed in mind, whenever conditions get too complex, information technology 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                  key                                      =                    {item.id}                                    >                                {item.championship}                                                      </div                  >                                ;                                            }                )                ;                                            }                                            }                            function              App              (              )              {              const              [items,              setItems]              =              useState              (              [              ]              )              ;              useEffect              (              (              )              =>              {              getItems              (              )              .              then              (              data              =>              setItems              (data)              )              ;              }              ,              [              ]              )              ;              return              (                                                <div                >                                                                                                                                <                    Listing                                    items                                      =                    {items}                                    fallback                                      =                    {                    "Loading..."                    }                                    />                                                                                                                          </div                >                            )              ;              }                      

Wrapping upwardly

When nosotros become such an mistake, nosotros 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, it might exist a practiced fourth dimension to extract the logic to a component.

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

lammonhimusince.blogspot.com

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

0 Response to "React Uncaught (in Promise) Typeerror: Cannot Read Property 'error' of Undefined"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel