Skip to content

Instantly share code, notes, and snippets.

@brookback
Last active May 13, 2019 09:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save brookback/26622ff6a7d11ed34f6e321cf79e81a4 to your computer and use it in GitHub Desktop.
Save brookback/26622ff6a7d11ed34f6e321cf79e81a4 to your computer and use it in GitHub Desktop.
A React hook for getting a single boolean value for when pairs in an array change.

useHasChanged

import React, { useState } from 'react';

interface Props {
  text: string;
}

const MyComponent = (props: Props) => {
  const [currentText, setText] = useState<string>(step.description);

  const hasChanged = useHasChanged([
    // hasChanged will be true if either of these values
    // change when compared to each other.
    [ currentText, props.text ]
  ]);

  return (
    <div>
      <input type="text" onInput={(evt) => setText(evt.currentTarget.value) } />
      <button disabled={!hasChanged}>Save<button>
    </div>
  );
};

Specify a custom comparator function as a third element in the array pair to do complex comparisons:

interface ComplexType {
    value: string;
}
const complex1: ComplexType = { value: 'foo' };
const complex2: ComplexType = { value: 'bar' };

const complexComparator: Comparator<ComplexType> = (a, b) =>
    return a.value === b.value;

const hasChangedComplex = useHasChanged([
  [ complex1, complex2, complexComparator ]
]);
import { useEffect, useState } from 'react';
/** Return true if `t1` and `t2` are the same. */
export type Comparator<T> = (t1: T, t2: T) => boolean;
export type HasChanged<T = any> = [T, T, Comparator<T>?];
const flatten = (arr: any[][]) => arr.reduce((arr, el) => [...arr, ...el]);
const removeNonPrimities = (arr: any[]) =>
arr.filter((a) => typeof a !== 'function');
/**
* Flatten input pair array and remove functions to get an array of dependencies
* for a React Hook.
*/
const getDependencies = (arr: HasChanged[]) => removeNonPrimities(flatten(arr));
const isSame: Comparator<any> = (t1, t2) => t1 === t2;
/**
* Hook for getting a boolean variable which indicates if specified pairs
* have changed. An optional third comparator function can be provided to
* be used when comparing the pair.
*/
const useHasChanged = (els: HasChanged[]) => {
const [hasChanged, setHasChanged] = useState(false);
useEffect(() => {
setHasChanged(els.some(([t1, t2, comp = isSame]) => !comp(t1, t2)));
}, getDependencies(els));
return hasChanged;
};
export default useHasChanged;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment