Cannot Read Property 'options' of Undefined Modal

React - Cannot read property 'map' of undefined

March 12, 2020 - 5 min read

If you lot are a react developer, in that location is a practiced chance that you faced this error couple of times:

TypeError: Cannot read property 'map' of undefined

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

The problem

In social club to understand what are the possible solutions, lets get-go understand what is the exact consequence here.

Consider this lawmaking block:

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

Nosotros take a component that manage a state of items, it also take an effect which inside it we run an asynchronous operation - getItems, which will return united states of america the data nosotros demand from the server, and then we call setItems with the received data every bit items. This component also renders the items - information technology iterate over information technology with .map and returning a react element for each item.

Merely we wont come across annihilation on the screen, well except the fault:

TypeError: Cannot read holding '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 information returned from the server:

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

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

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

What nearly our useEffect phone call though?

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

Possible solutions

#one 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([]) telephone call, it will render united states with

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

#2 Conditional rendering

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

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

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

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

Annotation that we removed the initial array for items.

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

The undefined or null values are ignored inside the context of JSX then its condom to laissez passer it on for the get-go render.

We could also use an else statement if we want 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              (              item              =>              {              return                                                <div                key                                  =                  {item.id}                                >                            {particular.title}                                                </div                >                            ;              }              )              ;                              }                else                {                                            itemsToRender                =                "Loading..."                ;                                            }                            return                                                <div                >                            {itemsToRender}                                                </div                >                            ;              }                      

#ii.5 Inline conditional rendering

Another option to conditionally render something in react, is to utilise the && logical operator:

                          part              App              (              )              {              const              [items,              setItems]              =              useState              (              )              ;              useEffect              (              (              )              =>              {              getItems              (              )              .              then              (              data              =>              setItems              (data)              )              ;              }              ,              [              ]              )              ;              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 ever evaluates to expression, and faux && expression always evaluates to false. Therefore, if the condition is true, the element right subsequently && volition appear in the output. If it is false, React volition ignore and skip information technology.

We can also use the conditional operator condition ? truthful : false if we want to render the Loading... text:

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

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

                          part              App              (              )              {                              const                [items,                setItems]                =                useState                (                [                ]                )                ;                            useEffect              (              (              )              =>              {              getItems              (              )              .              so              (              data              =>              setItems              (data)              )              ;              }              ,              [              ]              )              ;              return              (                                                <div                >                                                                                          {items                &&                items.length                >                0                                            ?                items.                map                (                item                =>                {                                            return                                                      <div                  primal                                      =                    {detail.id}                                    >                                {item.championship}                                                      </div                  >                                ;                                            }                )                                            :                "Loading..."                }                                                                                                          </div                >                            )              ;              }                      

Though keep in heed, whenever conditions become as well complex, it might be a bespeak for the states to extract that logic to a component:

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

Wrapping up

When nosotros get such an mistake, 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 become as well complex, it might be a proficient time to extract the logic to a component.

Promise you found this article helpful, if you lot take a dissimilar approach or any suggestions i would beloved to hear about them, you tin can tweet or DM me @sag1v. 🤓

jonesbece2002.blogspot.com

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

0 Response to "Cannot Read Property 'options' of Undefined Modal"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel