useEffect, but know what caused the effect to run
npm install use-change-aware-effectuseEffect doesn't provide enough info to decide if a side-effect should be run, and also which side-effect should be run:
useChangeAwareEffect works exactly like useEffect, but with less code and improved readability compared to using useRef.
npm install --save use-change-aware-effect
useChangeAwareEffect(changeAwareCallback({did, previous, changeCount, isMount}), dependencyObject)
useChangeAwareLayoutEffect(changeAwareCallback({did, previous, changeCount, isMount}), dependencyObject)
useEffect, but it's an object and not an array of dependencies. This makes the changeAwareCallback easier to use since you can refer to dependencies by their object key.
changeAwareCallback is executed whenever any of the values change between renders, or always when this parameter is omitted or undefined. React's Object.is implementation is used to detect changes.
useEffect, but is passed an object containing additional information about what changed between executions of the callback:
isMount: boolean true when the function is executed for the first time after the component using this hook is mounted.
did: object An object summarizing which dependencies changed since the previous execution of changeAwareCallback. The object contains the same keys as dependencyObject, and each value has properties:
change: boolean true when the dependency with the given key changed since the last execution (ex: did.foo.change). Always true after the initial render.
notChange: boolean true when the dependency with the given key did not change since the last execution (ex: did.bar.notChange). Always false after the initial render.
previous: object The dependencyObject passed to useChangeAwareEffect that triggered the previous execution of changeAwareCallback. During the initial render, the previous value for each dependency is undefined. Note that only a shallow copy of the previous dependencies are made - any external mutations will affect these values.
changeCount: number the number of dependencies from dependencyObject that changed since the previous execution of changeAwareCallback
useEffect, you can optionally return a function from changeAwareEffectCallback to perform any clean-up logic.
import { useChangeAwareEffect } from "use-change-aware-effect";
/**
* An example hook that shows how useChangeAwareEffect can simplify conditionally running an effect.
*
* The hook records whenever a user finishes all of the todos on their list
* by identifying when the list went from having some todos to having 0.
*
* Alternatively, this check could be made in all code paths that could remove todos,
* although useChangeAwareEffect centralizes this side-effect to one place.
*
* @param todos a list of todo-items for the user
*/
const useTodosEventTracking = (todos: any[]) => {
useChangeAwareEffect(
({ previous, isMount }) => {
if (!isMount && previous.todos.length > 0 && todos.length === 0) {
trackFinishedAllTodosEvent();
}
},
{ todos }
);
function trackFinishedAllTodosEvent() {
//record that the user finished all of their todos, maybe with something like google analytics
}
};
`
`
import React from "react";
import { useChangeAwareEffect } from "use-change-aware-effect";
/**
* An example hook to run a different side-effect based on what changed during the previous render.
*
* The hook is used to efficiently keep track of and reload values in a grid that has filters:
* - When any filters change, all of the rows and cell data need to be filtered and reloaded from scratch, which is expensive
* - When just new columns are added to the grid, only reloading cell data for the existing rows is neccessary, which is less expensive
*
*/
const useGridData = (gridFilterA: object, gridFilterB: object, gridColumns: Set) => {
const [gridData, setGridData] = React.useState `
Typescript Support
If using typescript, your IDE's auto-complete is aware of valid properties on the did and previous` objects: