Sails Cannot Read Property 'attributes' of Undefined

React - Cannot read holding 'map' of undefined

March 12, 2020 - v min read

If yous are a react developer, in that location is a proficient chance that you faced this mistake couple of times:

TypeError: Cannot read property 'map' of undefined

TL;DR - If you are non in the mode for reading or yous only desire the bottom line, and then here it is

The problem

In society to sympathise what are the possible solutions, lets first understand what is the verbal issue here.

Consider this code cake:

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

We have a component that manage a state of items, it also accept an effect which within information technology we run an asynchronous functioning - getItems, which will return usa the data we need from the server, and so we call setItems with the received information every bit items. This component also renders the items - information technology iterate over it with .map and returning a react chemical element for each item.

But we wont run into anything on the screen, well except the error:

TypeError: Cannot read holding 'map' of undefined

What's going on hither?

We practise have an items variable:

                          const              [items,              setItems]              =              useState              (              )              ;                      

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

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

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

  1. React renders (invoking) our component.
  2. React "run across" the useState telephone call and return u.s. [undefined, fn].
  3. React evaluate our return statement, when information technology hits the items.map(...) line its really running undefined.map(...) which is obviously an fault in JavaScript.

What about our useEffect telephone call though?

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

Possible solutions

#ane Initial value

One possible solution is to give your variable a default initial value, with useState information technology would look similar that:

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

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

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

#ii 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 return something else).

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

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

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

Note that we removed the initial array for items.

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

The undefined or null values are ignored inside the context of JSX then its prophylactic to pass it on for the first return.

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

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

#2.5 Inline conditional rendering

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

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

Why it works? The react docs explains it well:

It works because in JavaScript, true && expression always evaluates to expression, and false && expression ever evaluates to false. Therefore, if the condition is true, the element correct later && will appear in the output. If it is imitation, React will ignore and skip it.

Nosotros can besides use the provisional operator condition ? truthful : false if we want to return the Loading... text:

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

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

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

Though keep in mind, whenever weather become likewise complex, it might be a signal for u.s.a. to extract that logic to a component:

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

Wrapping up

When nosotros get such an error, we are probably getting the value in an asynchronous way. Nosotros should provide an initial value for our variable or conditionally render it or both. If our condition become besides complex, it might be a good time to excerpt the logic to a component.

Promise you lot found this article helpful, if you lot have a dissimilar approach or any suggestions i would love to hear near them, yous can tweet or DM me @sag1v. 🤓

greenearom1989.blogspot.com

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

0 Response to "Sails Cannot Read Property 'attributes' of Undefined"

ارسال یک نظر

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel