简体   繁体   中英

React - too many re-renders

So I am building a travel journal, please ignore the beauty of the code, I am still very new. Chrome is telling me there is too many re-renders however I don't know what is causing them.

import { useState, useEffect } from "react";
import Navbar from "./Navbar";
import Card from "./Card";
import Entry from "./Entry";
import { StorageContext } from "./Contexts/StorageContext";

function App(props) {
  const [storage, setStorage] = useState([
    {
      id: 213134234.12312342534631,
      title: "Mount Fuji",
      location: "JAPAN",
      googleMapsUrl: "https://goo.gl/maps/1DGM5WrWnATgkSNB8",
      startDate: "12 Jan, 2021",
      endDate: "24 Jan, 2021",
      description:
        "Mount Fuji is the tallest mountain in Japan, standing at 3,776 meters     (12,380 feet). Mount Fuji is the single most popular tourist site in Japan, for both     Japanese and foreign tourists.",
      imageUrl: "https://source.unsplash.com/WLxQvbMyfas",
    },
    {
      id: 2391452351832031.21315124,
      title: "Sydney Opera House",
      location: "AUSTRALIA",
      googleMapsUrl:
        "https://www.google.com/maps/d/embed?    mid=1NYBTZlF3StQEf65_sVbpMlskCoo&ie=UTF8&hl=en&msa=0&ll=-33.857595813227405%2C151.21484    352721822&spn=0.035636%2C0.042915&z=17&output=embed",
      startDate: "27 May, 2021",
      endDate: "8 Jun, 2021",
      description:
        "The Sydney Opera House is a multi-venue performing arts centre in Sydney. Located on the banks of the Sydney Harbour, it is often regarded as one of the 20th century's most famous and distinctive buildings.",
      imageUrl: "https://source.unsplash.com/JmuyB_LibRo",
    },
    {
      id: 213944551.231569123957,
      title: "Geirangerfjord",
      location: "NORWAY",
      googleMapsUrl:
        "https://www.google.com/maps/place/Geirangerfjord/@62.1047779,6.9351325,11z/data=!4m13!1m7!3m6!1s0x46169d427b268c51:0xb8c99540dcc397fe!2sGeirangerfjord!3b1!8m2!3d62.101506!4d7.0940817!3m4!1s0x46169d427b268c51:0xb8c99540dcc397fe!8m2!3d62.101506!4d7.0940817",
      startDate: "01 Oct, 2021",
      endDate: "18 Nov, 2021",
      description:
        "The Geiranger Fjord is a fjord in the Sunnmøre region of Møre og Romsdal     county, Norway. It is located entirely in the Stranda Municipality.",
  imageUrl: "https://source.unsplash.com/3PeSjpLVtLg",
    },
  ]);
  const newLog = props.handleSubmit;
  setStorage((prevState) => {
    return {
      ...prevState,
      newLog,
    };
  });

  return (
    <div>
      <Navbar />
      <Entry />
      <StorageContext value={{ storage, setStorage }}>
        <Card />
      </StorageContext>
    </div>
  );
}

export default App;

I am really confused because im not sure how to debug the re-renders exactly. Any help or direction where to find relevant information would be greatly appreciated.

Like Giorgi says, you should never use useState() in the render function. What happens is, React fires the render function, it then updates the state, which triggers a rerender and thus the render function again. This creates an infinite loop.

Use useState above the render function. It will trigger only once then.

You are getting that error because you are updating the state directly

setStorage((prevState) => {
    return {
      ...prevState,
      newLog,
    };
});

So when the component parses the code it reaches setStorage, update the state component re-renders again it updates the state and component re-renders, henceforth an infinite loop which is the reason you are getting too many re-renders error

Either move that code inside a function and pass the function as a context value or maybe perform this logic from the component where you are gonna call setStorage

I think, from reading your code, that what you want to accomplish is to add new entries into your state. Is this correct?

If it is, you would generally want to define a function to do this for you, and pass this function along to components further down the component tree.

If this function is already defined (could be what you're passing in as handleSubmit ) further up the component tree, then I think you should also move this component state up. Define the function and the state in the same place.

A quick example:

export default function App(){
  const [storage, setStorage] = useState([]) // empty array to save space in example

  const addEntry = useCallback((entry) => {
    setStorage(prevState => ([...prevState, entry])
  }, [])

  return (
    <ChildComponent entries={storage} handleSubmit={addEntry} />
  )
}

In this example, you would be able to call handleSubmit inside ChildComponent , passing in an object to add to the list. It would in turn update the state, and pass down the updated state to ChildComponent .

If you're new to React, be aware that some hooks use a dependency array. useCallback is one of those. The dependency array should include every variable, including functions, that are accessed inside the hook. There are a few exceptions, like for example setState functions returned from useState . This is because React knows these functions will never change, so they are safe to exclude.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM