Skip to content

Suggestion: Add correct version of fetchData example in "A Complete Guide to useEffect" #367

@SleeplessByte

Description

@SleeplessByte

TL;DR: There is actually no solution given to the initial "issue". I recommend repeating the Comment component with the correct usage of useEffect.

Context

In the recent article A Complete Guide to useEffect, which is amazingly well written, there is a section "Don't lie to react about dependencies":

Lying to React about dependencies has bad consequences. Intuitively, this makes sense, but I’ve seen pretty much everyone who tries useEffect with a mental model from classes try to cheat the rules. (And I did that too at first!)

function Comment({ fetchData }) {
  useEffect(() => {
    fetchData().then(...);
  }, []); // This is okay, right? Nope. 😞
}

“But I only want to run it on mount!”, you’ll say. For now, remember: if you specify deps, all values from inside your component that are used by the effect must be there. Including props, state, functions — anything in your component.

Sometimes when you do that, it causes a problem. For example, maybe you see an infinite refetching loop, or a socket is recreated too often. The solution to that problem is not to remove a dependency. We’ll look at the solutions soon.

But before we jump to solutions, let’s understand the problem better.

In the last sentence it actually points that there will be a solution to this particular problem.

The issue, as you read on, is that fetchData might change, but because there are no dependencies listed, it won't ever run again. So perhaps the solution is to "Move the function inside the effect":

function App() {
  const [data, setData] = useState({ hits: [] });

  async function fetchData() {
    const result = await axios(
      'https://hn.algolia.com/api/v1/search?query=react',
    );
    setData(result.data);
  }

  useEffect(() => {
    fetchData();
  }, []); // Is this okay?

  // ...

This is a great example because it actually uses very similar code to the initial issue. I also think it's confusing, because weren't we fetching a Comment and now it's doing a "generic search"? Also, where did the Comment component go?

Naturally this can be a disjunct example, which is fine, but all the other examples are around the Counter concept, which is very cohesive and therefore clear to follow and see the differences in implementation.

Scrolling down, this last example is broken down and shown how to use deps correctly:

const [query, setQuery] = useState('react');

useEffect(() => {
  function getFetchUrl() {
    return 'https://hn.algolia.com/api/v1/search?query=' + query;
  }

async function fetchData() {
  const result = await axios(getFetchUrl());
    setData(result.data);
  }

  fetchData();
}, [query]); // ✅ Deps are OK

And then it's moved back into a component called Example. Why it's not called Example here and why it was App before is beyond me, I think it increases cognitive complexity as it's difficult, if you don't understand these hooks well enough yet, what is important, what isn't and most importantly: what are the invariants?

After this and another variations + explanation on this, the subject seems closed until we reach "In closing".

The problem

Personally, I don't think the original question was every answered: "What is the solution to []". The answer seems to be "it depends", but I don't think it's explicitly written out. I think that using the different class names makes it harder to follow.

  • Can I pass my fetch function as a prop?
  • Should I use all the deps of the fetch function in deps or the function itself (and risking an infinite loop, depending on how the function is created, and more specifically where).
  • Should I replace my fetch function with useCallback? Or should I use useCalback and pass that as a prop?
  • Should I use observables because I see .subscribe and .unsubscribe?
  • What was so wrong about the first version anyway?

These are not my questions, but questions my employees had when reading the article.

The suggestion

Repeat the original problematic code just before in-closing, and fix it with everything we've learned above. Alternatively, change Comment to Example or Article, so that there is a "fixed" version down the line.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requesthelp wantedExtra attention is needed

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions