React: Hooks: useEffect + context

Created on 10 Nov 2018  路  5Comments  路  Source: facebook/react

Can I use useEffect() in conjunction with useContext().
Meaning, I would like the useEffect() to rerun when the context changes.

For example:

const MyComponent = (props) => {
  const ctx = useContext(MyContext)

  useEffect( () => {
    //do some useful operation, when the ctx changes.
  }, [ctx])
}

Do you want to request a feature or report a bug?
possibly a bug

What is the current behavior?
ctx does not work with useEffect.

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem. Your bug will get fixed much faster if we can run your code and it doesn't have dependencies other than React. Paste the link to your JSFiddle (https://jsfiddle.net/Luktwrdm/) or CodeSandbox (https://codesandbox.io/s/new) example below:

What is the expected behavior?

Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?
16.7.0-alpha.0

Most helpful comment

Ideally you would do this:

const MyComponent = (props) => {
  const { a, b, c, d } = useContext(MyContext)

  useEffect(() => {
    // Do stuff
  }, [a, b, c, d])
}

But if you really want to do what you're doing, then this will do the job:

const MyComponent = (props) => {
  const ctx = useContext(MyContext)

  useEffect(() => {
    // Do stuff
  }, [...Object.values(ctx)])
}

All 5 comments

useEffect will check if ctx changed with ===; this means that there will be changes only if ctx is a different object.

Having not seen your provider, it's possible you're accidentally only changing a property in an object without changing the object itself; that will never trigger a context update.

Ideally you would do this:

const MyComponent = (props) => {
  const { a, b, c, d } = useContext(MyContext)

  useEffect(() => {
    // Do stuff
  }, [a, b, c, d])
}

But if you really want to do what you're doing, then this will do the job:

const MyComponent = (props) => {
  const ctx = useContext(MyContext)

  useEffect(() => {
    // Do stuff
  }, [...Object.values(ctx)])
}

@arianon, Kovenaky... Thank you. This should do the trick instead of the whole object.

Total nitpick: I don't think you have to spread the result - it could just be:

useEffect( () => {

}, Object.values(ctx) )

:)

I just ran into this issue, and I confirm that the spreading of ...Object.values(ctx) matters.

My theory is that Object.values returns an array, which means that mutations within the array do not trigger re-renders. The spreading is the surest way to proceed.

Was this page helpful?
0 / 5 - 0 ratings