Typeerror: Cannot Read Property 'timeline' of Undefined

React - Cannot read property 'map' of undefined

March 12, 2020 - v min read

If y'all are a react programmer, in that location is a expert chance that you faced this fault couple of times:

TypeError: Cannot read property 'map' of undefined

TL;DR - If y'all are not in the mode for reading or you merely desire the bottom line, then hither it is

The problem

In gild to understand what are the possible solutions, lets first empathize what is the exact issue here.

Consider this code cake:

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

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

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

TypeError: Cannot read property 'map' of undefined

What'south going on here?

We exercise take an items variable:

                          const              [items,              setItems]              =              useState              (              )              ;                      

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

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

Well lets examine how the react catamenia looks like in our case:

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

What about our useEffect phone call though?

React will run all furnishings after the return is committed to the screen, which means we can'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 similar that:

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

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

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

#ii Conditional rendering

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

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

                          // ⚠️ wont work!!              export              default              function              App              (              )              {              // ....              render              (                                                <div                >                                                                      {                              if                (items)                {                                            items.                map                (                detail                =>                (                                                                                  <div                  key                                      =                    {detail.id}                                    >                                {particular.title}                                                      </div                  >                                                            )                )                                            }                            }                                                                                          </div                >                            )              ;              }                      

Just 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              (              )              .              then              (              data              =>              setItems              (information)              )              ;              }              ,              [              ]              )              ;                              allow                itemsToRender;                                            if                (items)                {                                            itemsToRender                =                items.                map                (                item                =>                {                                            render                                                      <div                  key                                      =                    {item.id}                                    >                                {detail.title}                                                      </div                  >                                ;                                            }                )                ;                                            }                                            render                                                      <div                  >                                {itemsToRender}                                                      </div                  >                                ;                            }                      

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

We could also use an else argument if nosotros want to render something else like a spinner or some text:

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

#ii.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              (              )              .              and so              (              data              =>              setItems              (data)              )              ;              }              ,              [              ]              )              ;              return              (                                                <div                >                                                                                          {items                &&                items.                map                (                item                =>                {                                            return                                                      <div                  cardinal                                      =                    {item.id}                                    >                                {detail.title}                                                      </div                  >                                ;                                            }                )                }                                                                                                          </div                >                            )              ;              }                      

Why it works? The react docs explains it well:

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

We can also utilize the conditional operator status ? truthful : false if we desire to render the Loading... text:

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

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

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

Though continue in heed, whenever atmospheric condition become too complex, information technology might be a signal for us to extract that logic to a component:

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

Wrapping up

When we get such an error, we 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 also complex, information technology might exist a proficient fourth dimension to extract the logic to a component.

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

buchananthersom2002.blogspot.com

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

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

Publicar un comentario

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel