It's React's useEffect hook, except using deep comparison on the inputs, not reference equality
WARNING: Please only use this if you really can't find a way to use
React.useEffect
. There's often a better way to do what you're trying to do than a deep comparison.
React's built-in useEffect
hook has a second argument called
the "dependencies array" and it allows you to optimize when React will call your
effect callback. React will do a comparison between each of the values (via
Object.is
) to determine whether your effect callback should be
called.
The problem is that if you need to provide an object for one of those dependencies and that object is new every render, then even if none of the properties changed, your effect will get called anyway.
Here's an example situation:
function Query({query, variables}) {
// some code...
React.useEffect(
() => {},
// because of the way the Query component is used below, `variables` is a
// new object every render. This is the problem.
[query, variables],
)
return <div>{/* awesome UI here */}</div>
}
function QueryPageThing({username}) {
const query = `
query getUserData($username: String!) {
user(login: $username) {
name
}
}
`
const variables = {username}
// poof! Every render `variables` will be a new object!
return <Query query={query} variables={variables} />
}
NOTE: you could also solve this problem if the
QueryPageThing
created the variables object like this:const variables = React.useMemo(() => ({username}), [username])
. Then you wouldn't need this package. But sometimes you're writing a custom hook and you don't have control on what kinds of things people are passing you (or you want to give them a nice ergonomic API that can handle new objects every render).
This is a drop-in replacement for React.useEffect
for this use-case only.
Note, if you try to use
useDeepCompareEffect
with only primitive values, you will receive an error because you should useReact.useEffect
instead.
This module is distributed via npm which is bundled with node and should be installed as one of your project's dependencies:
npm install --save use-deep-compare-effect
You use it in place of React.useEffect
.
NOTE: Only use this if your values are objects or arrays that contain objects. Otherwise, you should just use
React.useEffect
. In case of "polymorphic" values (eg: sometimes object, sometimes a boolean), useuseDeepCompareEffectNoCheck
, but do it at your own risk, as maybe there can be better approaches to the problem.
Example:
import React from 'react'
import ReactDOM from 'react-dom'
import useDeepCompareEffect from 'use-deep-compare-effect'
function Query({query, variables}) {
// some code...
useDeepCompareEffect(
() => {
// make an HTTP request or whatever with the query and variables
// optionally return a cleanup function if necessary
},
// query is a string, but variables is an object. With the way Query is used
// in the example above, `variables` will be a new object every render.
// useDeepCompareEffect will do a deep comparison and your callback is only
// run when the variables object actually has changes.
[query, variables],
)
return <div>{/* awesome UI here */}</div>
}
Looking to contribute? Look for the Good First Issue label.
Please file an issue for bugs, missing documentation, or unexpected behavior.
Please file an issue to suggest new features. Vote on feature requests by adding a π. This helps maintainers prioritize what to work on.
Thanks goes to these people (emoji key):
Kent C. Dodds π» π π |
Edygar de Lima Oliveira π» |
Justin Dorfman π |
Anton Halim π |
MichaΓ«l De Boey π» |
Tobias BΓΌschel π |
This project follows the all-contributors specification. Contributions of any kind welcome!