Protractor Cannot Read Property 'bind' of Undefined

React - Cannot read property 'map' of undefined

March 12, 2020 - v min read

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

TypeError: Cannot read holding 'map' of undefined

TL;DR - If y'all are non in the style for reading or yous but want the bottom line, then here it is

The problem

In lodge to sympathize what are the possible solutions, lets outset sympathise what is the exact issue here.

Consider this lawmaking block:

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

Nosotros take a component that manage a state of items, it besides take an event which within it we run an asynchronous functioning - getItems, which volition return us 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 information technology with .map and returning a react element for each item.

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

TypeError: Cannot read property 'map' of undefined

What's going on here?

Nosotros do have an items variable:

                          const              [items,              setItems]              =              useState              (              )              ;                      

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

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

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

  1. React renders (invoking) our component.
  2. React "see" the useState call and render 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 fault in JavaScript.

What about our useEffect telephone call though?

React will run all effects later on the render is committed to the screen, which ways we tin't avoid a commencement render without our data.

Possible solutions

#1 Initial value

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

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

This means that when react runs our useState([]) call, information technology will return united states of america with

Which means that in the first render of our component, react will "see" our items every bit an empty array, then instead of running undefined.map(...) like before, it will run [].map(...).

#2 Conditional rendering

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

When working with JSX we tin can't merely throw some if else statements within our tree:

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

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

Notation that we removed the initial assortment for items.

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

The undefined or null values are ignored inside the context of JSX and so its safety to laissez passer information technology on for the first return.

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

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

#two.5 Inline conditional rendering

Some other option to conditionally return something in react, is to use the && logical operator:

                          function              App              (              )              {              const              [items,              setItems]              =              useState              (              )              ;              useEffect              (              (              )              =>              {              getItems              (              )              .              and so              (              information              =>              setItems              (information)              )              ;              }              ,              [              ]              )              ;              return              (                                                <div                >                                                                                          {items                &&                items.                map                (                particular                =>                {                                            return                                                      <div                  fundamental                                      =                    {item.id}                                    >                                {item.title}                                                      </div                  >                                ;                                            }                )                }                                                                                                          </div                >                            )              ;              }                      

Why it works? The react docs explains it well:

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

Nosotros tin also use the provisional operator condition ? true : false if we want to render the Loading... text:

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

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

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

Though go on in mind, whenever conditions become also complex, it might be a bespeak for us to extract that logic to a component:

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

Wrapping up

When nosotros 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 return it or both. If our condition become too complex, it might be a practiced time to extract the logic to a component.

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

tetreaultchising.blogspot.com

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

0 Response to "Protractor Cannot Read Property 'bind' of Undefined"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel