Typeerror Cannot Read Property 'map' of Undefined Jest React

React - Cannot read property 'map' of undefined

March 12, 2020 - 5 min read

If you are a react programmer, in that location is a good take chances that yous faced this mistake couple of times:

TypeError: Cannot read property 'map' of undefined

TL;DR - If you are not in the mode for reading or you simply want the bottom line, then hither information technology is

The trouble

In order to understand what are the possible solutions, lets first sympathize what is the exact issue hither.

Consider this lawmaking block:

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

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

Just we wont see anything on the screen, well except the mistake:

TypeError: Cannot read property 'map' of undefined

What'southward going on hither?

Nosotros do take an items variable:

                          const              [items,              setItems]              =              useState              (              )              ;                      

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

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

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

  1. React renders (invoking) our component.
  2. React "see" the useState phone call and return us [undefined, fn].
  3. React evaluate our render statement, when information technology hits the items.map(...) line its really running undefined.map(...) which is patently an error in JavaScript.

What about our useEffect telephone call though?

React will run all effects after the render is committed to the screen, which ways we can't avoid a showtime render without our data.

Possible solutions

#ane Initial value

One possible solution is to give your variable a default initial value, with useState information technology would look like that:

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

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

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

#2 Conditional rendering

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

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

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

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

Annotation 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                (                item                =>                {                                            return                                                      <div                  key                                      =                    {item.id}                                    >                                {detail.championship}                                                      </div                  >                                ;                                            }                )                ;                                            }                                            render                                                      <div                  >                                {itemsToRender}                                                      </div                  >                                ;                            }                      

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

We could as well use an else statement if we desire to return something else similar a spinner or some text:

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

#2.5 Inline conditional rendering

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

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

Why it works? The react docs explains it well:

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

Nosotros tin also 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                (                particular                =>                {                                            render                                                      <div                  key                                      =                    {item.id}                                    >                                {item.title}                                                      </div                  >                                ;                                            }                )                                            :                "Loading..."                }                                                                                                          </div                >                            )              ;              }                      

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

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

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

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

Wrapping up

When nosotros get such an fault, nosotros are probably getting the value in an asynchronous way. We should provide an initial value for our variable or conditionally render it or both. If our condition get as well circuitous, it might be a expert time to excerpt the logic to a component.

Hope y'all found this commodity helpful, if you accept a dissimilar approach or whatever suggestions i would dearest to hear nigh them, you lot can tweet or DM me @sag1v. 🤓

phillipsristraid1999.blogspot.com

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

0 Response to "Typeerror Cannot Read Property 'map' of Undefined Jest React"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel