Home > Enterprise >  Re Render After Updating DB
Re Render After Updating DB

Time:12-17

I have a this component in which I fetch data from an API and display it on screen:

const RestaurantsList = () => {
  const [restaurants, setRestaurants] = useState([]);

  useEffect(() => {
    const fetchData = async () => {
      const response = await fetch("http://localhost:3001/api/v1/restaurants");
      const data = await response.json();
      //console.log(data);
      setRestaurants(data);
    };
    fetchData();
  }, []);
...

I have another component AddRestaurant in which I make a Post request to the API to add a new restaurant:

const AddRestaurant = () => {
  const [name, setName] = useState("");
  const [location, setLocation] = useState("");
  const [priceRange, setPriceRange] = useState("");

  function nameUpdate(e) {
    setName(e.target.value);
  }
  function locationUpdate(e) {
    setLocation(e.target.value);
  }

  const handleSubmit = async function (e) {
    //e.preventDefault();

    try {
      await fetch("http://localhost:3001/api/v1/restaurants", {
        method: "POST",
        made: "cors",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          name,
          location,
          price_range: priceRange,
        }),
      });
    } catch (err) {
      console.log(err);
    }
    setName("");
    setLocation("");
    setPriceRange("");
  };
...

The problem is that when I add a new Restaurant I want to add tho the list without refreshing the page. If I add a [restaurants] dependency on the useEffect, it keeps making GET request in loop.

Both components are child og this component:

const Home = () => {
  return (
    <div>
      <Header />
      <AddRestaurant />
      <RestaurantsList />
    </div>
  );
};

export default Home;

What is the best solution?

CodePudding user response:

One solution would be to add a top-level state that starts off as true and fetches initial data. We set this to false when data fetching is done.

const Home = () => {
  const [fetchRestaurants, setFetchRestaurants] = useState(true)

  return (
    <div>
      <Header />
      <AddRestaurant setFetchRestaurants={setFetchRestaurants} />
      <RestaurantsList fetchRestaurants={fetchRestaurants} setFetchRestaurants={setFetchRestaurants} />
    </div>
  )
}

export default Home
const RestaurantsList = ({ fetchRestaurants, setFetchRestaurants }) => {
  const [restaurants, setRestaurants] = useState([])

  useEffect(() => {
    if (fetchRestaurants) {
      const fetchData = async () => {
        const response = await fetch('http://localhost:3001/api/v1/restaurants')
        const data = await response.json()
        // console.log(data);
        setRestaurants(data)
      }
      fetchData()
      setFetchRestaurants(false)
    }
  }, [fetchRestaurants, setFetchRestaurants])

  // ...
}

Then in AddRestaurant:

const handleSubmit = async function (e) {
  // ...
  setFetchRestaurants(true)
  setName('')
  setLocation('')
  setPriceRange('')
}

When fetchRestaurants changes, RestaurantsList will re-rerender and fetch new data.

A library that does a lot of this for you is RTK Query, check out the docs here:

CodePudding user response:

We should use some kind of flag that will inform components about new updates.
I would recommend doing something like this.

export default function Home () {
  const [
    timeOfLastRestaurantCreation,
    setTimeOfLastRestaurantCreation
  ] = useState<string>()

  return (
    <div>
      <Header />
      <AddRestaurant
        onAddRestaurant={() => {
          setTimeOfLastRestaurantCreation(new Date().toISOString())
        }}
      />
      <RestaurantsList
        timeOfLastRestaurantCreation={timeOfLastRestaurantCreation} 
      />
    </div>
  )
}

PS. Why ISOString instead of Date? Easier to debug.

  • Related