Cannot Read Property 'lift' of Undefined at Tapoperatorfunction

React - Cannot read property 'map' of undefined

March 12, 2020 - five min read

If you are a react programmer, there is a good chance that you faced this error couple of times:

TypeError: Cannot read property 'map' of undefined

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

The problem

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

Consider this code block:

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

We have a component that manage a country of items, it too have an consequence which inside it we run an asynchronous performance - getItems, which volition return u.s.a. the data we need from the server, then we call setItems with the received data equally items. This component also renders the items - it iterate over it with .map and returning a react element for each detail.

Merely we wont see anything on the screen, well except the error:

TypeError: Cannot read property 'map' of undefined

What's going on hither?

We practise accept an items variable:

                          const              [items,              setItems]              =              useState              (              )              ;                      

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

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

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

  1. React renders (invoking) our component.
  2. React "encounter" the useState call and return united states of america [undefined, fn].
  3. React evaluate our return statement, when it hits the items.map(...) line its actually running undefined.map(...) which is manifestly an mistake in JavaScript.

What about our useEffect phone call though?

React will run all effects subsequently the return is committed to the screen, which means we can't avoid a first render without our information.

Possible solutions

#1 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, it will render us with

Which means that in the showtime 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 render 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 just throw some if else statements inside our tree:

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

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

Annotation 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                  central                                      =                    {item.id}                                    >                                {item.title}                                                      </div                  >                                ;                                            }                )                ;                                            }                                            return                                                      <div                  >                                {itemsToRender}                                                      </div                  >                                ;                            }                      

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

We could likewise use an else argument if we desire 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              (              particular              =>              {              return                                                <div                fundamental                                  =                  {particular.id}                                >                            {detail.title}                                                </div                >                            ;              }              )              ;                              }                else                {                                            itemsToRender                =                "Loading..."                ;                                            }                            return                                                <div                >                            {itemsToRender}                                                </div                >                            ;              }                      

#2.5 Inline conditional rendering

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

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

Why information technology 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 chemical element right subsequently && volition appear in the output. If information technology is false, React volition ignore and skip it.

Nosotros can also use the conditional operator condition ? true : false if we want to return the Loading... text:

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

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

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

Though continue in listen, whenever conditions become too complex, it might be a signal for u.s. to extract that logic to a component:

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

Wrapping upwardly

When nosotros become 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 too circuitous, it might be a good time to extract the logic to a component.

Promise y'all establish this article helpful, if y'all have a different approach or any suggestions i would honey to hear well-nigh them, y'all tin can tweet or DM me @sag1v. 🤓

quirionunfinamess.blogspot.com

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

0 Response to "Cannot Read Property 'lift' of Undefined at Tapoperatorfunction"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel