Cannot Read Property 'map' of Undefined Redux

React - Cannot read property 'map' of undefined

March 12, 2020 - 5 min read

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

TypeError: Cannot read property 'map' of undefined

TL;DR - If you lot are non in the mode for reading or you just desire the bottom line, and so here it is

The problem

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

Consider this lawmaking block:

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

Nosotros have a component that manage a state of items, it also take an result which inside it we run an asynchronous operation - getItems, which volition return u.s. the data nosotros need from the server, then we call setItems with the received information equally items. This component also renders the items - it iterate over it with .map and returning a react chemical element for each particular.

But we wont run into anything on the screen, well except the error:

TypeError: Cannot read property '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 information returned from the server:

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

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

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

What almost our useEffect phone call though?

React will run all effects afterward the return is committed to the screen, which means we can't avert a first return without our data.

Possible solutions

#1 Initial value

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

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

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

Which ways that in the outset render of our component, react will "come across" our items equally an empty array, so instead of running undefined.map(...) like before, it volition run [].map(...).

#2 Conditional rendering

Another possible solution is to conditionally render the items, significant if we have the items then render them, else don't render (or render something else).

When working with JSX nosotros tin't simply throw some if else statements within our tree:

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

But instead we can create a variable exterior our tree and populate information technology conditionally:

Notation that nosotros removed the initial array for items.

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

The undefined or cipher values are ignored inside the context of JSX so its safe to laissez passer it on for the first render.

We could besides employ an else statement if we 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}                                >                            {item.title}                                                </div                >                            ;              }              )              ;                              }                else                {                                            itemsToRender                =                "Loading..."                ;                                            }                            render                                                <div                >                            {itemsToRender}                                                </div                >                            ;              }                      

#2.5 Inline conditional rendering

Some other pick to conditionally return something in react, is to use the && logical operator:

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

Why it works? The react docs explains it well:

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

We can likewise apply the provisional operator status ? true : false if we want to render the Loading... text:

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

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

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

Though keep in heed, whenever conditions become also 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                {                                            render                items.                map                (                item                =>                {                                            return                                                      <div                  key                                      =                    {item.id}                                    >                                {particular.title}                                                      </div                  >                                ;                                            }                )                ;                                            }                                            }                            function              App              (              )              {              const              [items,              setItems]              =              useState              (              [              ]              )              ;              useEffect              (              (              )              =>              {              getItems              (              )              .              so              (              data              =>              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 way. Nosotros should provide an initial value for our variable or conditionally render it or both. If our condition become too complex, it might be a good time to extract the logic to a component.

Hope you found this article helpful, if you lot have a dissimilar approach or whatsoever suggestions i would love to hear nearly them, yous tin can tweet or DM me @sag1v. 🤓

kanesully1994.blogspot.com

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

0 Response to "Cannot Read Property 'map' of Undefined Redux"

Postar um comentário

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel