Typeerror: Cannot Read Property 'message' of Undefined

React - Cannot read belongings 'map' of undefined

March 12, 2020 - 5 min read

If you are a react developer, there is a skillful chance that yous faced this fault couple of times:

TypeError: Cannot read property 'map' of undefined

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

The trouble

In lodge to empathise what are the possible solutions, lets offset understand what is the exact issue here.

Consider this code block:

                          // Only a data fetching function              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              (information)              )              ;              }              ,              [              ]              )              ;              return              (                                                <div                >                                                        {items.              map              (              item              =>              (                                                <div                key                                  =                  {particular.id}                                >                            {item.title}                                                </div                >                            )              )              }                                                                            </div                >                            )              ;              }                      

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

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

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 information technology with our data returned from the server:

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

Well lets examine how the react menstruum looks similar in our example:

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

What nigh our useEffect phone call though?

React will run all effects after the render is committed to the screen, which means we tin't avert a first render 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 like that:

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

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

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

#ii Provisional rendering

Another possible solution is to conditionally render the items, meaning if we have the items 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 work!!              export              default              role              App              (              )              {              // ....              return              (                                                <div                >                                                                      {                              if                (items)                {                                            items.                map                (                detail                =>                (                                                                                  <div                  key                                      =                    {item.id}                                    >                                {item.championship}                                                      </div                  >                                                            )                )                                            }                            }                                                                                          </div                >                            )              ;              }                      

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

Notation that we removed the initial array for items.

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

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

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

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

#2.5 Inline conditional rendering

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

                          function              App              (              )              {              const              [items,              setItems]              =              useState              (              )              ;              useEffect              (              (              )              =>              {              getItems              (              )              .              so              (              data              =>              setItems              (data)              )              ;              }              ,              [              ]              )              ;              return              (                                                <div                >                                                                                          {items                &&                items.                map                (                detail                =>                {                                            return                                                      <div                  fundamental                                      =                    {item.id}                                    >                                {item.title}                                                      </div                  >                                ;                                            }                )                }                                                                                                          </div                >                            )              ;              }                      

Why information technology 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 faux. Therefore, if the status is true, the element right after && will appear in the output. If it is faux, React will ignore and skip it.

We can besides use the provisional operator status ? truthful : false if we want to render the Loading... text:

                          part              App              (              )              {              const              [items,              setItems]              =              useState              (              )              ;              useEffect              (              (              )              =>              {              getItems              (              )              .              then              (              data              =>              setItems              (data)              )              ;              }              ,              [              ]              )              ;              render              (                                                <div                >                                                                                          {items                              ?                items.                map                (                particular                =>                {                                            return                                                      <div                  fundamental                                      =                    {item.id}                                    >                                {detail.championship}                                                      </div                  >                                ;                                            }                )                                            :                "Loading..."                }                                                                                                          </div                >                            )              ;              }                      

We can also mix both solutions, i.e: initial value with provisional rendering:

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

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

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

Wrapping up

When we get such an mistake, we 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, information technology might be a good fourth dimension to excerpt the logic to a component.

Promise y'all constitute this article helpful, if you accept a dissimilar approach or any suggestions i would love to hear about them, yous can tweet or DM me @sag1v. 🤓

friendtherinceple.blogspot.com

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

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

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel