Uncaught Typeerror: Cannot Read Property 'map' of Null

React - Cannot read property 'map' of undefined

March 12, 2020 - v min read

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

TypeError: Cannot read property 'map' of undefined

TL;DR - If you are not in the style for reading or you lot only want the bottom line, so hither it is

The problem

In order to understand what are the possible solutions, lets starting time understand what is the exact outcome here.

Consider this code block:

                          // Simply a data fetching function              const              fetchURL              =              "https://jsonplaceholder.typicode.com/todos/"              ;              const              getItems              =              (              )              =>              fetch              (fetchURL)              .              so              (              res              =>              res.              json              (              )              )              ;              role              App              (              )              {              const              [items,              setItems]              =              useState              (              )              ;              useEffect              (              (              )              =>              {              getItems              (              )              .              so              (              data              =>              setItems              (data)              )              ;              }              ,              [              ]              )              ;              return              (                                                <div                >                                                        {items.              map              (              item              =>              (                                                <div                key                                  =                  {item.id}                                >                            {item.title}                                                </div                >                            )              )              }                                                                            </div                >                            )              ;              }                      

We have a component that manage a state of items, information technology also accept an outcome which within it we run an asynchronous operation - getItems, which will render u.s. the data we 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 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 have an items variable:

                          const              [items,              setItems]              =              useState              (              )              ;                      

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

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

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

  1. React renders (invoking) our component.
  2. React "meet" the useState call and return us [undefined, fn].
  3. React evaluate our render statement, when it hits the items.map(...) line its actually running undefined.map(...) which is patently an mistake in JavaScript.

What about our useEffect call though?

React will run all furnishings after the render is committed to the screen, which ways we can't avoid a kickoff render without our data.

Possible solutions

#i Initial value

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

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

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

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

#2 Conditional rendering

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

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

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

Simply instead we can create a variable exterior our tree and populate it conditionally:

Notation that nosotros removed the initial assortment for items.

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

The undefined or null values are ignored inside the context of JSX and then its rubber to pass it on for the beginning render.

Nosotros could besides 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              (data)              )              ;              }              ,              [              ]              )              ;              let              itemsToRender;              if              (items)              {              itemsToRender              =              items.              map              (              item              =>              {              return                                                <div                key                                  =                  {particular.id}                                >                            {item.championship}                                                </div                >                            ;              }              )              ;                              }                else                {                                            itemsToRender                =                "Loading..."                ;                                            }                            return                                                <div                >                            {itemsToRender}                                                </div                >                            ;              }                      

#2.five 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              (              )              .              and then              (              information              =>              setItems              (information)              )              ;              }              ,              [              ]              )              ;              return              (                                                <div                >                                                                                          {items                &&                items.                map                (                item                =>                {                                            render                                                      <div                  key                                      =                    {item.id}                                    >                                {particular.championship}                                                      </div                  >                                ;                                            }                )                }                                                                                                          </div                >                            )              ;              }                      

Why it works? The react docs explains it well:

Information technology works because in JavaScript, true && expression e'er evaluates to expression, and false && expression always evaluates to simulated. Therefore, if the condition is truthful, the element correct after && volition announced in the output. If it is false, React volition ignore and skip information technology.

We tin can besides use the conditional operator status ? true : false if we want to render the Loading... text:

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

We tin as well mix both solutions, i.east: initial value with conditional rendering:

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

Though proceed in mind, whenever conditions become also complex, it might be a signal for usa to extract that logic to a component:

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

Wrapping upwardly

When we get such an fault, nosotros are probably getting the value in an asynchronous fashion. We should provide an initial value for our variable or conditionally render it or both. If our status get as well circuitous, it might exist a good fourth dimension to extract the logic to a component.

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

moricehatted.blogspot.com

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

Related Posts

0 Response to "Uncaught Typeerror: Cannot Read Property 'map' of Null"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel