16

I have the following code in FC component:

I just want to call the Api and Log the info when the component is mounted

The console.log is being called twice for empty array and twice for setting the same values.

import * as React from"react";
import Header from"../components/Header";
import Search from"../components/Search";
import Categories from"../components/Categories";
import Carousel from"../components/Carousel";
import CarouselItem from"../components/CarouselItem";
import Footer from"../components/Footer";
import "../assets/styles/App.scss";

const App = () => {
  const [videos, setVideos] = React.useState([]);

  React.useEffect(() => {
    fetch("http://localhost:3000/initalState")
      .then((response) => response.json())
      .then((data) => setVideos(data));
  }, []);

  console.log(videos);
  return (
    <div className="App">
      <Header></Header>
      <Search></Search>

      <Categories title="Mi Lista">
        <Carousel>
          <CarouselItem />
          <CarouselItem />
          <CarouselItem />
          <CarouselItem />
          <CarouselItem />
        </Carousel>
      </Categories>

      <Categories title="Tendencias">
        <Carousel>
          <CarouselItem />
          <CarouselItem />
        </Carousel>
      </Categories>

      <Categories title="Originales de Platzi Video">
        <Carousel>
          <CarouselItem />
        </Carousel>
      </Categories>

      <Footer />
    </div>
  );
};

export default App;

However, i got the following output:

enter image description here

Calling within useEffect:

  React.useEffect(() => {
    fetch("http://localhost:3000/initalState")
      .then((response) => response.json())
      .then((data) => {
        setVideos(data);
        console.log(videos);
      });
  }, []);

returns an empty array.

Juan Bonoso
  • 722
  • 1
  • 5
  • 15

2 Answers2

47

I just realized I was rendering App in strict Mode, which invokes some events twice:

Strict mode can’t automatically detect side effects for you, but it can help you spot them by making them a little more deterministic. This is done by intentionally double-invoking the following functions:

Class component constructor, render, and shouldComponentUpdate methods Class component static getDerivedStateFromProps method Function component bodies State updater functions (the first argument to setState) Functions passed to useState, useMemo, or useReducer

I had this:

ReactDOM.render(
      <React.StrictMode>
        <App />
      </React.StrictMode>,
      document.getElementById("root")
    );

Now

ReactDOM.render(<App />, document.getElementById("root"));

It's solved.

Nick Vu
  • 14,512
  • 4
  • 21
  • 31
Juan Bonoso
  • 722
  • 1
  • 5
  • 15
2

you can use UseCallback to avoid an additional run below is the sample code.

Note: If you directly call setTimeout/server calls inside use effect without wrapping in useCallback , it will be called twice

const App = () => {
  const [myData, setMyData] = React.useState([]);


  const getData = useCallback ( () => { 
    setTimeout(() => {
      console.log("Inside setTimeOut");
      setMyData("HEllo");
    }, 2000);

  }, [] )

  useEffect(() => {
    getData()
     console.log("Inside UseEffect",myData);
   },[getData]);


  return (
    <div className="App">
     Inside my App {myData}
    </div>
  );
}

export default App;

Output:

Inside UseEffect  [printed just once]
upog
  • 4,965
  • 8
  • 42
  • 81
  • I understand. Should i use console.logs outside the useEffect hooks? Same level as useEffect, return and getData? – Juan Bonoso May 10 '20 at 18:11
  • Nope. Then it will have more cycles , as getdata will have new data which will render again and prints log again. By wrapping i `useEffect` and adding dependency it will not run unless dependency changes – upog May 10 '20 at 18:31
  • I have removed all the `myData` dependencies and kept the other `console` prints. It prints `Inside UseEffect` twice – Shan Biswas Aug 08 '22 at 17:14