admin管理员组

文章数量:1131394

Given a simple hook function useFoo with a simple function foo.

When I use a function inside of useEffect, everything appears to function fine, but I get a waring from exhaustive-deps saying that function must be listed as a dependency.

When I add the function to the deps array it causes the effect to fire repeatedly or even continuously depending on the situation.

Why is foo not stable? Or how do I make the warning go away, and keep my code working properly?

const useFoo = () => {
  const foo = () => {
    return 'foo'
  }
  return {
    foo
  }
}

export default useFoo

Used in a control without dep

  useEffect(() => {
    console.log('i fire 2 times because of React.Strict')
  }, [])

Used in a control with dep

  useEffect(() => {
    console.log('i fire many times')
  }, [foo])

Given a simple hook function useFoo with a simple function foo.

When I use a function inside of useEffect, everything appears to function fine, but I get a waring from exhaustive-deps saying that function must be listed as a dependency.

When I add the function to the deps array it causes the effect to fire repeatedly or even continuously depending on the situation.

Why is foo not stable? Or how do I make the warning go away, and keep my code working properly?

const useFoo = () => {
  const foo = () => {
    return 'foo'
  }
  return {
    foo
  }
}

export default useFoo

Used in a control without dep

  useEffect(() => {
    console.log('i fire 2 times because of React.Strict')
  }, [])

Used in a control with dep

  useEffect(() => {
    console.log('i fire many times')
  }, [foo])
Share Improve this question edited 2 days ago Jason Hernandez asked Jan 8 at 16:57 Jason HernandezJason Hernandez 2,9711 gold badge19 silver badges31 bronze badges 2
  • 1 const foo = () => { return 'foo'; } creates a new arrow function and assigns it to foo every time you call your hook. Why do you think it should be stable? – knittl Commented Jan 8 at 17:00
  • Because "foo" is not stable? The useFoo hook returns an object literal, i.e. { foo }, and foo is a new function reference each time, so it's a new object reference each time when used as a dependency for the useEffect hook. – Drew Reese Commented Jan 8 at 17:00
Add a comment  | 

2 Answers 2

Reset to default 1

UseCallback needs to be added to the foo function to make it stable.

const useFoo = () => {
  const foo = useCallback(() => {
    return 'foo'
  }, [])
  return {
    foo
  }
}
const useFoo = () => {
  const foo = () => { // <- this creates a new function every time the hook is called
    return 'foo'
  }
  return { // <- this creates a new object every time the hook is called
    foo
  }
}

The function is completely stateless and independent of the enclosing hook. Consequently, it can be moved outside the hook so that only a single instance of it exists:

const foo = () => {
  return 'foo'
}

const useFoo = () => {
  return {
    foo
  }
}

Moving stateless and independent functions out of the hook is cleaner and cheaper than using yet another hook to cache the function instance (the function instances are still created when executing your hook, they are then simply discarded and ignored).

You can do the same with the object literal, which doesn't depend on anything from the hook:

const foo = () => {
  return 'foo'
}

const fooObj = {
  foo
}

const useFoo = () => {
  return fooObj
}

But then the question becomes why do you have a hook in the first place if you don't use any hook functionality? Just call your foo function directly.

本文标签: