Uncaught Typeerror: Cannot Read Property 'maps' of Undefined

React - Cannot read belongings 'map' of undefined

March 12, 2020 - 5 min read

If you are a react developer, at that place is a good chance that you faced this fault couple of times:

TypeError: Cannot read property 'map' of undefined

TL;DR - If you are not in the fashion for reading or yous just want the bottom line, and so hither it is

The problem

In order to empathise what are the possible solutions, lets first understand what is the verbal issue here.

Consider this lawmaking cake:

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

We have a component that manage a state of items, it also have an effect which inside information technology we run an asynchronous operation - getItems, which will return us the data we need from the server, then we telephone call setItems with the received information as items. This component too renders the items - it iterate over it with .map and returning a react element for each item.

But we wont run across anything on the screen, well except the fault:

TypeError: Cannot read belongings 'map' of undefined

What's going on here?

We do have 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 flow looks similar in our instance:

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

What nearly our useEffect call though?

React will run all effects after the render is committed to the screen, which means nosotros can't avert a first render without our information.

Possible solutions

#ane Initial value

Ane possible solution is to requite your variable a default initial value, with useState it would await like that:

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

This ways that when react runs our useState([]) call, it will render u.s.a. with

Which means that in the first render of our component, react will "see" our items as an empty array, and then instead of running undefined.map(...) like earlier, it volition run [].map(...).

#2 Conditional rendering

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

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

                          // ⚠️ wont piece of work!!              export              default              function              App              (              )              {              // ....              return              (                                                <div                >                                                                      {                              if                (items)                {                                            items.                map                (                item                =>                (                                                                                  <div                  primal                                      =                    {detail.id}                                    >                                {particular.championship}                                                      </div                  >                                                            )                )                                            }                            }                                                                                          </div                >                            )              ;              }                      

But instead nosotros tin create a variable outside our tree and populate it conditionally:

Note that we removed the initial array for items.

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

The undefined or cypher values are ignored inside the context of JSX and so its safe to pass information technology on for the commencement return.

Nosotros could also apply an else statement if nosotros want to render something else similar a spinner or some text:

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

#two.5 Inline conditional rendering

Some other 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                  key                                      =                    {detail.id}                                    >                                {item.title}                                                      </div                  >                                ;                                            }                )                }                                                                                                          </div                >                            )              ;              }                      

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

It works considering in JavaScript, true && expression always evaluates to expression, and fake && expression always evaluates to false. Therefore, if the condition is truthful, the element right subsequently && will appear in the output. If it is false, React will ignore and skip information technology.

We tin besides utilise the conditional operator condition ? true : imitation if we want to render the Loading... text:

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

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

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

Though keep in mind, whenever conditions become besides complex, it might be a signal for usa to excerpt that logic to a component:

                                          part                List                (                                  {                  items,                  fallback                  }                                )                {                                            if                (                !items                ||                items.length                ===                0                )                {                                            render                fallback;                                            }                else                {                                            return                items.                map                (                item                =>                {                                            return                                                      <div                  key                                      =                    {item.id}                                    >                                {detail.title}                                                      </div                  >                                ;                                            }                )                ;                                            }                                            }                            function              App              (              )              {              const              [items,              setItems]              =              useState              (              [              ]              )              ;              useEffect              (              (              )              =>              {              getItems              (              )              .              then              (              information              =>              setItems              (information)              )              ;              }              ,              [              ]              )              ;              return              (                                                <div                >                                                                                                                                <                    List                                    items                                      =                    {items}                                    fallback                                      =                    {                    "Loading..."                    }                                    />                                                                                                                          </div                >                            )              ;              }                      

Wrapping up

When we go such an error, we are probably getting the value in an asynchronous mode. We should provide an initial value for our variable or conditionally render it or both. If our condition go as well complex, it might exist a skilful time to excerpt the logic to a component.

Hope you found this article helpful, if y'all have a different approach or any suggestions i would beloved to hear nearly them, you tin can tweet or DM me @sag1v. 🤓

isaaccalluser.blogspot.com

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

0 Response to "Uncaught Typeerror: Cannot Read Property 'maps' of Undefined"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel