20
const useSomeHook = ({number}) => {
  const [newNumber, setNewNumber] = useState(0)

  useEffect(() => {
    setNewNumber(number + 1)
  }, [number])
}

const SomeComponent = ({number, value, ...restProps}) => {

  useSomeHook({number})


  return <div>{number}</div>
}

Let's imagine I have this case. Each time when in SomeComponent come some new prop, it will call my useSomeHook hook, but I want to prevent it. I want to call it only when the number is changed (memoize it). In other cases, don't touch it. But I haven't found any solving with this case. Could you help me solve this issue?

sdgluck
  • 24,894
  • 8
  • 75
  • 90
Andrey Radkevich
  • 3,012
  • 5
  • 25
  • 57
  • 1
    The `useEffect` hook within `useSomeHook` will only be invoked when the dependency `number` changes. – sdgluck Apr 26 '20 at 09:43
  • 1
    So I don't see what memoization gives you in this case. – sdgluck Apr 26 '20 at 09:44
  • In this case it will be ok, but imagine that I have some hard logic in this hook, and it invoked each time for example I type something with redux form , and it works horrible – Andrey Radkevich Apr 26 '20 at 09:58
  • What you pass in the second argument for `useEffect` will trigger subsequent invocation of the callback you pass in as the first argument. To address your ask, you can do two things: 1. Add in-depth equality check as the second param (this requires some work), and/or 2. Add a condition in the callback; ex: `if (obj.a !== obj.b) callback()` – Amir Jun 04 '21 at 17:10
  • use `useRef` instead of `useState` – Khaled Osman Apr 28 '23 at 10:07

2 Answers2

11

You can not prevent calling hook, this will lead to invariant violation error. Every hook in component should be executed on each render. You should rely on useEffect dependencies argument to run conditional code only if value changes.

Alex
  • 1,724
  • 13
  • 25
2

use useRef instead of useState to memoize/cache the returned value so that its not recomputed when its used across components, or when there are multiple instances of that component

const useSomeHook = ({number}) => {
  const numberRef = useRef(0)

  useEffect(() => {
    numberRef.current = numberRef.current + 1
  }, [number])
}

const SomeComponent = ({number, value, ...restProps}) => {

  useSomeHook({number})


  return <div>{number}</div>
}

it also sounds like you want to use useMemo instead of useEffect

const useSomeHook = ({number}) => {
  const numberRef = useRef(0)

  cachedValue = useMemo(() => {
    return numberRef.current + 1
  }, [number])
   return cachedValue
}

const SomeComponent = ({number, value, ...restProps}) => {

  const cachedValue = useSomeHook({number})


  return <div>{number}</div>
}
Khaled Osman
  • 1,251
  • 12
  • 17
  • what if our `useSomeHook` is making an api call, it that case `useRef` might not be a good thing to use as well, thoughts ? – Prateek Aug 12 '23 at 01:14
  • @Prateek Why not? I would argue that using useRef especially when making api calls is even better because you can use it to cache the api call response, otherwise if you use the same hook across multiple components, you would be making multiple api calls – Khaled Osman Aug 16 '23 at 07:55