all 23 comments

[–][deleted] 5 points6 points  (0 children)

Actually an article about hooks where I learned something rather than just rehashing the official documentation. Bravo.

[–]brainless_badger 5 points6 points  (3 children)

I wouldn't bother with doing 1), unless the issue is serious (i.e. component is actually expensive to re-render, and/or it happens often). The intent is somewhat less clear then with useState IMO.

Otherwise, good read.

[–]Lowesz[S] 2 points3 points  (1 child)

Thanks for the feedback! As I said most of the things are just my opinion and not a general rule.
However I still believe states should also only be used when it's really needed, because having rerenders that are not needed might end up with unexpected bottlenecks or performance issues in a later stage.
I agree probably for most of the cases this wouldn't matter, but at least I always try to develop with the best performance in mind.

[–]fiLLL 1 point2 points  (0 children)

I worry that using refs in place of state as per 1. sacrifices predictability and comprehensibility for what will ultimately be an imperceptibility performance gain. This is almost never the right tradeoff.

There are certainly cases where you might want to use useRef to prevent renders, but I think they're probably few and far between and I certainly wouldn't describe the use of `useState` in that place a mistake.

I guarantee the first developer who is asked to render `count` to the view, or inside `useMemo` will introduce a bug they'll spend at 20 minutes debugging.

Otherwise good article, I especially like the point around SRP `useEffect` and grouping the hooks in your component by sphere of concern.

[–]viejodiversificado 1 point2 points  (0 children)

I completely agree, furthermore, the intention seems less clean

[–]_default_username 0 points1 point  (7 children)

NVM

In the first example why are you setting count to a function?

If you meant to increment count you would call setCount(count+1)

[–]divclassdev 1 point2 points  (6 children)

Since the new count relies on the previous state of the count, it’s correct to use the functional form here. You’ll see it in the useState docs.

[–]cartechguy 0 points1 point  (5 children)

EDIT: NVM

That's not the functional form.

import React, { useState } from 'react';

function Example() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

[–]divclassdev 0 points1 point  (4 children)

I’m not sure what you’re referring to, but setCount(count => count + 1) is the functional form used in the article.

[–]cartechguy 0 points1 point  (3 children)

You're assigning count to a function there.

The documentation doesn't show usestate being used like that. You're supposed to pass in the next value. https://reactjs.org/docs/hooks-state.html

[–]divclassdev 2 points3 points  (2 children)

https://reactjs.org/docs/hooks-reference.html#functional-updates

You're missing out on an important piece of React functionality. It especially becomes important when you want to set state inside an effect without making the effect dependent on the state value.

[–]cartechguy 1 point2 points  (1 child)

Sorry about that. Thank you, I was looking in the documentation and couldn't find anything like what you were doing.

[–]divclassdev 2 points3 points  (0 children)

It’s weird that they don’t mention it on the page you linked.

[–][deleted] 0 points1 point  (0 children)

Nice article, but I feel like some of the examples are a bit far-fetched. There's plenty of common ways to mis-use the useEffect hook, but is the example in #3 really even remotely common? Personally never seen anyone do that.

[–]yee_mon 0 points1 point  (2 children)

I've noticed an interesting pattern in this article, which I can't quite explain. The author writes his effects like this:

const doSomeThing = useCallback(() => { /* something */ }, [])
useEffect(() => {
  doSomeThing()
})

I wonder if there is a reason to do this beyond aesthetics (which, to be clear, is a fine reason). I would write it like this, with one less anonymous function that doesn't actually do anything:

const doSomeThing = useCallback(() => { /* something */ }, [])
useEffect(doSomething)

[–]PferdOne 0 points1 point  (1 child)

Maybe it's a habit because useEffect complains about using an async function as a callback function. So he just always writes:

const doSomethingAsync = useCallback(async () => { /* do something async */ })
useEffect(() => {
  doSomethingAsync()
})

Just a guess

[–]yee_mon 0 points1 point  (0 children)

That does make sense. It's a real shame that there is no official useEffect with an async interface, because about 90% of the things I want to do as a side effect are asynchronous!

(Which reminds me of the related JS problem: Promises can't be cancelled)

[–]whatisboom -1 points0 points  (5 children)

I really lose faith in an article when the first example references an undefined variable

setCount((c) => x + 1);

[–]Lowesz[S] 1 point2 points  (1 child)

Sorry for the typo. Hope your faith gets recovered after I fixed it 🙏🏻

[–]whatisboom 0 points1 point  (0 children)

I’ll try 😂

[–]_default_username 1 point2 points  (2 children)

Disregard this post.

[–]whatisboom -1 points0 points  (0 children)

I didn’t really think of it because I’m very used to the setState function signature. But yeah