Skip to content Skip to sidebar Skip to footer

Cannot Read Property 'render' of Undefined Fullcalendar

React - Cannot read property 'map' of undefined

March 12, 2020 - 5 min read

If you are a react developer, there is a good take chances that you faced this mistake couple of times:

TypeError: Cannot read property 'map' of undefined

TL;DR - If you lot are not in the manner for reading or you just want the bottom line, so here it is

The problem

In order to understand what are the possible solutions, lets showtime sympathize what is the exact consequence here.

Consider this code block:

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

We have a component that manage a state of items, it also have an effect which inside it we run an asynchronous operation - getItems, which will return us the data we need from the server, then nosotros call setItems with the received information as items. This component likewise renders the items - information technology iterate over it 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 exercise 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 case:

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

What about our useEffect call though?

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

Possible solutions

#1 Initial value

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

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

This ways that when react runs our useState([]) call, it 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 assortment, so instead of running undefined.map(...) like before, it will run [].map(...).

#2 Conditional rendering

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

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

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

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

The undefined or null values are ignored inside the context of JSX and so its safe to pass it on for the first render.

We could also utilize an else argument if we desire to render something else similar a spinner or some text:

                          role              App              (              )              {              const              [items,              setItems]              =              useState              (              )              ;              useEffect              (              (              )              =>              {              getItems              (              )              .              so              (              data              =>              setItems              (data)              )              ;              }              ,              [              ]              )              ;              allow              itemsToRender;              if              (items)              {              itemsToRender              =              items.              map              (              detail              =>              {              render                                                <div                key                                  =                  {detail.id}                                >                            {detail.title}                                                </div                >                            ;              }              )              ;                              }                else                {                                            itemsToRender                =                "Loading..."                ;                                            }                            return                                                <div                >                            {itemsToRender}                                                </div                >                            ;              }                      

#2.5 Inline provisional rendering

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

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

Why it works? The react docs explains it well:

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

Nosotros can also use the conditional operator condition ? true : faux if nosotros want to render the Loading... text:

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

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

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

Though keep in listen, whenever conditions become too circuitous, it might be a point for us to extract that logic to a component:

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

Wrapping upwards

When we 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 render it or both. If our condition become too complex, information technology might be a good time to extract the logic to a component.

Promise you establish this article helpful, if you take a dissimilar arroyo or any suggestions i would love to hear almost them, you can tweet or DM me @sag1v. 🤓

vanoverpophe1936.blogspot.com

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

Post a Comment for "Cannot Read Property 'render' of Undefined Fullcalendar"