Skip to content Skip to sidebar Skip to footer

Cannot Read Property 'extendoptions' of Undefined Mount

React - Cannot read holding 'map' of undefined

March 12, 2020 - 5 min read

If you lot are a react developer, at that place is a expert run a risk that you faced this mistake couple of times:

TypeError: Cannot read property 'map' of undefined

TL;DR - If yous are not in the mode for reading or you but want the bottom line, then here information technology is

The problem

In order to empathize what are the possible solutions, lets beginning empathise what is the verbal issue here.

Consider this lawmaking block:

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

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

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

TypeError: Cannot read property 'map' of undefined

What's going on here?

We do accept an items variable:

                          const              [items,              setItems]              =              useState              (              )              ;                      

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

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

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

  1. React renders (invoking) our component.
  2. React "run across" 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 call though?

React will run all effects later on the render is committed to the screen, which means nosotros tin't avert a outset render without our data.

Possible solutions

#1 Initial value

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

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

This ways that when react runs our useState([]) telephone call, information technology volition return us with

Which means that in the get-go render of our component, react will "see" our items as an empty assortment, so instead of running undefined.map(...) like earlier, it volition run [].map(...).

#2 Conditional rendering

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

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

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

Merely instead we can create a variable outside our tree and populate it 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                  primal                                      =                    {item.id}                                    >                                {detail.title}                                                      </div                  >                                ;                                            }                )                ;                                            }                                            render                                                      <div                  >                                {itemsToRender}                                                      </div                  >                                ;                            }                      

The undefined or aught values are ignored inside the context of JSX and then its safe to pass it on for the outset render.

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

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

#two.five Inline provisional rendering

Another option to conditionally render 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                (                particular                =>                {                                            return                                                      <div                  cardinal                                      =                    {particular.id}                                    >                                {item.title}                                                      </div                  >                                ;                                            }                )                }                                                                                                          </div                >                            )              ;              }                      

Why it works? The react docs explains it well:

It works considering in JavaScript, truthful && expression e'er evaluates to expression, and simulated && expression ever evaluates to false. Therefore, if the condition is true, the element right after && will appear in the output. If it is simulated, React will ignore and skip information technology.

We tin too use the conditional operator condition ? truthful : imitation if we want to render the Loading... text:

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

Nosotros can too mix both solutions, i.e: initial value with provisional rendering:

                          function              App              (              )              {                              const                [items,                setItems]                =                useState                (                [                ]                )                ;                            useEffect              (              (              )              =>              {              getItems              (              )              .              then              (              information              =>              setItems              (data)              )              ;              }              ,              [              ]              )              ;              return              (                                                <div                >                                                                                          {items                &&                items.length                >                0                                            ?                items.                map                (                detail                =>                {                                            return                                                      <div                  key                                      =                    {detail.id}                                    >                                {detail.championship}                                                      </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                List                (                                  {                  items,                  fallback                  }                                )                {                                            if                (                !items                ||                items.length                ===                0                )                {                                            render                fallback;                                            }                else                {                                            return                items.                map                (                detail                =>                {                                            render                                                      <div                  key                                      =                    {item.id}                                    >                                {item.title}                                                      </div                  >                                ;                                            }                )                ;                                            }                                            }                            part              App              (              )              {              const              [items,              setItems]              =              useState              (              [              ]              )              ;              useEffect              (              (              )              =>              {              getItems              (              )              .              then              (              information              =>              setItems              (information)              )              ;              }              ,              [              ]              )              ;              return              (                                                <div                >                                                                                                                                <                    List                                    items                                      =                    {items}                                    fallback                                      =                    {                    "Loading..."                    }                                    />                                                                                                                          </div                >                            )              ;              }                      

Wrapping upwards

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 also complex, it might be a good fourth dimension to extract the logic to a component.

Hope you found this article helpful, if you lot take a different approach or any suggestions i would dear to hear nearly them, you can tweet or DM me @sag1v. 🤓

johnsonimand1958.blogspot.com

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

Postar um comentário for "Cannot Read Property 'extendoptions' of Undefined Mount"