Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

useEffect doesn't run after rendering

I'm kind of confused about how useEffect is triggered and how it work. I wrote a function like this but the useEffect doesn't run at all. I want to fetch the data from the API and then render a page based on the data. But it doesn't trigger the useEffect. If I don't use the useEffect, it will render the page three times.

async function getData() {
  var tmpArrData = [];
  await fetch("this API is hidden due to the privacy of the company - sorry")
    .then((res) => res.json())
    .then((data) => {
      console.log("data", data);
      tmpArrData = data;
  });
  console.log("tmpData ", tmpArrData);
  return tmpArrData;
}

function App() {

  const [arrData, setArrData] = useState();
  const [loadData, setLoadData] = useState(false);

  useEffect(() => {
    console.log("if it works, this line should be shown");
    const tmpArrData = getData();
    setArrData(tmpArrData);
  }, [arrData]);


  const data = arrData[0];
  console.log(data);

  return (
      <GifCompoment 
      id = {data.id}
      name = {data.name}
      activeTimeTo = {data.activeTimeTo}
      activeTimeFrom = {data.activeTimeFrom}
      requiredPoints = {data.requiredPoints}
      imageUrl = {data.imageUrl}
      />
  );
}

export default App;

like image 523
Hoangdz Avatar asked Aug 31 '25 01:08

Hoangdz


1 Answers

The useEffect hook is guaranteed to run at least once at the end of the initial render.

getData is an async function and the useEffect callback code is not waiting for it to resolve. Easy solution is to chain from the implicitly returned Promise from getData and access the resolved value to update the arrData state. Make sure to remove the state from the useEffect's dependency array so that you don't create a render loop.

The getData implementation could be clean/tightened up by just returning the fetch result, no need to save into a temp variable first.

async function getData() {
  return await fetch(".....")
    .then((res) => res.json());
}

useEffect(() => {
  console.log("if it works, this line should be shown");
  getData().then((data) => {
    setArrData(data);
  });
}, []); // <-- empty dependency so effect called once on mount

Additionally, since arrData is initially undefined, arrData[0] is likely to throw an error. You may want to provide valid initial state, and a fallback value in case the first element is undefined, so you don't attempt to access properties of an undefined object.

const [arrData, setArrData] = useState([]);

...

const data = arrData[0] || {}; // data is at least an object

return (
  <GifCompoment 
    id={data.id}
    name={data.name}
    activeTimeTo={data.activeTimeTo}
    activeTimeFrom={data.activeTimeFrom}
    requiredPoints={data.requiredPoints}
    imageUrl={data.imageUrl}
  />
);
like image 65
Drew Reese Avatar answered Sep 03 '25 15:09

Drew Reese