Typeerror: Cannot Read Property 'catch' of Undefined

React - Cannot read property 'map' of undefined

March 12, 2020 - 5 min read

If you are a react developer, there is a proficient run a risk that yous faced this mistake couple of times:

TypeError: Cannot read belongings 'map' of undefined

TL;DR - If you are not in the style for reading or yous just want the lesser line, so hither information technology is

The problem

In social club to understand what are the possible solutions, lets first sympathize what is the exact effect here.

Consider this code block:

                          // Merely a data fetching office              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              (              item              =>              (                                                <div                key                                  =                  {item.id}                                >                            {item.championship}                                                </div                >                            )              )              }                                                                            </div                >                            )              ;              }                      

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

But we wont see annihilation on the screen, well except the error:

TypeError: Cannot read property 'map' of undefined

What'due south going on here?

Nosotros exercise have an items variable:

                          const              [items,              setItems]              =              useState              (              )              ;                      

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

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

Well lets examine how the react flow looks similar in our case:

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

What about our useEffect call though?

React volition run all effects after the return is committed to the screen, which ways we can't avert a first render without our data.

Possible solutions

#1 Initial value

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

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

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

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

#2 Provisional rendering

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

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

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

Just instead we can create a variable outside our tree and populate information technology conditionally:

Note that we removed the initial array for items.

                          role              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                  >                                ;                                            }                )                ;                                            }                                            return                                                      <div                  >                                {itemsToRender}                                                      </div                  >                                ;                            }                      

The undefined or nothing values are ignored within the context of JSX so its safe to pass it on for the beginning return.

We could also use an else statement if we want to return something else like a spinner or some text:

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

#2.5 Inline conditional rendering

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

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

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

It works because in JavaScript, true && expression always evaluates to expression, and false && expression always evaluates to false. Therefore, if the status is truthful, the chemical element correct afterwards && volition announced in the output. If information technology is false, React will ignore and skip information technology.

We tin also use the conditional operator condition ? true : fake if we want to render the Loading... text:

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

We can also mix both solutions, i.due 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                =>                {                                            render                                                      <div                  key                                      =                    {item.id}                                    >                                {item.title}                                                      </div                  >                                ;                                            }                )                                            :                "Loading..."                }                                                                                                          </div                >                            )              ;              }                      

Though go on in mind, whenever conditions become also circuitous, it might be a signal for us to extract that logic to a component:

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

Wrapping up

When we become such an mistake, we are probably getting the value in an asynchronous style. Nosotros should provide an initial value for our variable or conditionally render it or both. If our condition go too complex, information technology might be a adept time to excerpt the logic to a component.

Hope you plant this article helpful, if you have a dissimilar arroyo or any suggestions i would beloved to hear about them, you can tweet or DM me @sag1v. 🤓

kooptheawaster.blogspot.com

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

Related Posts

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

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel