Search code examples
reactjsreact-hooksuse-effect

Is it wrong to fetch an API without using the useEffect Hook?


I've been doing it this way but some colleges told me that I should use the useEffect Hook instead. The problem is that I don't see the benefit of that approach and I think that my approach is cleaner.

import React, { useState, useEffect } from "react";

const fetchTheApi = () =>
  new Promise(res => setTimeout(() => res({ title: "Title fetched" }), 3000));

const UseEffectlessComponent = () => {
  const [data, setData] = useState();
  !data && fetchTheApi().then(newData => setData(newData));
  return <h1>{data ? data.title : "No title"}</h1>;
};

const UseEffectComponent = () => {
  const [data, setData] = useState();
  useEffect(() => {
    fetchTheApi().then(newData => setData(newData));
  }, []);
  return <h1>{data ? data.title : "No title"}</h1>;
};

const MyComponent = () => (
  <div>
    <UseEffectlessComponent />
    <UseEffectComponent />
  </div>
);

Edit based on responses:

I changed the code to re render, like this:

import React, { useState, useEffect } from 'react';

const fetchTheApi = (origin) => {
    console.log('called from ' + origin);
    return new Promise((res) =>
        setTimeout(() => res({ title: 'Title fetched' }), 3000)
    );
};

const UseEffectlessComponent = () => {
    const [data, setData] = useState();
    !data &&
        fetchTheApi('UseEffectlessComponent').then((newData) => setData(newData));
    return <h1>{data ? data.title : 'No title'}</h1>;
};

const UseEffectComponent = () => {
    const [data, setData] = useState();
    useEffect(() => {
        fetchTheApi('UseEffectComponent').then((newData) => setData(newData));
    }, []);
    return <h1>{data ? data.title : 'No title'}</h1>;
};

const MyComponent = () => {
    const [counter, setCounter] = useState(0);
    counter < 3 && setTimeout(() => setCounter(counter + 1), 1000);
    return (
        <div>
            <p>counter is: {counter}</p>
            <UseEffectlessComponent />
            <UseEffectComponent />
        </div>
    );
};

In the console I got:

called from UseEffectlessComponent called from UseEffectComponent called from UseEffectlessComponent called from UseEffectlessComponent called from UseEffectlessComponent

So, I finally found the benefit to that approach. I've got some code to change... Thanks a lot for the answers!


Solution

  • Right now, if your component re-renders before it has set the data it will attempt to fetch the data again leading to multiple fetches. Considering you only want to fetch data once and not accidentally multiple times it would be better to put it in the useEffect.