Cannot Read Property Function of Undefined Sinon

React - Cannot read property 'map' of undefined

March 12, 2020 - 5 min read

If you are a react developer, there is a good chance that y'all faced this fault couple of times:

TypeError: Cannot read holding 'map' of undefined

TL;DR - If y'all are non in the style for reading or you but want the bottom line, so here information technology is

The problem

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

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              (              data              =>              setItems              (information)              )              ;              }              ,              [              ]              )              ;              return              (                                                <div                >                                                        {items.              map              (              item              =>              (                                                <div                fundamental                                  =                  {item.id}                                >                            {item.championship}                                                </div                >                            )              )              }                                                                            </div                >                            )              ;              }                      

We have a component that manage a state of items, information technology also take an effect which inside information technology we run an asynchronous operation - getItems, which will render us the data nosotros 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 item.

But nosotros wont see annihilation on the screen, well except the fault:

TypeError: Cannot read holding 'map' of undefined

What's going on here?

Nosotros do have an items variable:

                          const              [items,              setItems]              =              useState              (              )              ;                      

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

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

Well lets examine how the react catamenia looks like 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 it hits the items.map(...) line its actually running undefined.map(...) which is obviously an error in JavaScript.

What almost our useEffect call though?

React will run all effects after the render is committed to the screen, which ways we can't avert a showtime render without our data.

Possible solutions

#ane Initial value

One possible solution is to requite your variable a default initial value, with useState it would expect like that:

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

This means that when react runs our useState([]) call, it will return u.s. with

Which means that in the kickoff render of our component, react will "see" our items every bit an empty array, so instead of running undefined.map(...) like earlier, information technology will run [].map(...).

#2 Provisional 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 nosotros can't just throw some if else statements inside our tree:

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

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

Note that we removed the initial array for items.

                          office              App              (              )              {              const              [items,              setItems]              =              useState              (              )              ;              useEffect              (              (              )              =>              {              getItems              (              )              .              and then              (              data              =>              setItems              (data)              )              ;              }              ,              [              ]              )              ;                              permit                itemsToRender;                                            if                (items)                {                                            itemsToRender                =                items.                map                (                item                =>                {                                            return                                                      <div                  fundamental                                      =                    {item.id}                                    >                                {item.title}                                                      </div                  >                                ;                                            }                )                ;                                            }                                            return                                                      <div                  >                                {itemsToRender}                                                      </div                  >                                ;                            }                      

The undefined or nothing values are ignored inside the context of JSX then its safe to pass it on for the get-go render.

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

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

#2.5 Inline conditional rendering

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

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

Why information technology works? The react docs explains information technology well:

Information technology works because in JavaScript, true && expression always evaluates to expression, and false && expression always evaluates to simulated. Therefore, if the status is true, the element right afterwards && volition appear in the output. If it is false, React will ignore and skip it.

We tin can also apply the conditional operator condition ? true : false if we want to render the Loading... text:

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

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

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

Though keep in mind, whenever weather become too complex, it might exist a point for united states of america to extract that logic to a component:

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

Wrapping up

When we go such an fault, we are probably getting the value in an asynchronous way. We should provide an initial value for our variable or conditionally return it or both. If our status become too complex, it might exist a good time to extract the logic to a component.

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

ricecamraithe.blogspot.com

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

0 Response to "Cannot Read Property Function of Undefined Sinon"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel