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.
TL;DR: There is actually no solution given to the initial "issue". I recommend repeating the
Commentcomponent with the correct usage ofuseEffect.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":
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
fetchDatamight 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":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
Commentand now it's doing a "generic search"? Also, where did theCommentcomponent go?Naturally this can be a disjunct example, which is fine, but all the other examples are around the
Counterconcept, 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
depscorrectly:And then it's moved back into a component called
Example. Why it's not calledExample hereand why it wasAppbefore 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.fetchfunction as a prop?fetchfunction indepsor the function itself (and risking an infinite loop, depending on how the function is created, and more specifically where).useCallback? Or should I useuseCalbackand pass that as a prop?.subscribeand.unsubscribe?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
CommenttoExampleorArticle, so that there is a "fixed" version down the line.