Skip to content

Instantly share code, notes, and snippets.

@gladchinda
Last active December 25, 2020 19:35
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 gladchinda/e3336318f1a71c9943ad8d47f48a9cde to your computer and use it in GitHub Desktop.
Save gladchinda/e3336318f1a71c9943ad8d47f48a9cde to your computer and use it in GitHub Desktop.
A custom React hook for managing state as an object.
import { useState, useEffect, useRef, useCallback } from 'react';
const OBJECT_TYPE = '[object Object]';
const $type = Function.prototype.call.bind(Object.prototype.toString);
const $has = Function.prototype.call.bind(Object.prototype.hasOwnProperty);
export default function useObjectState(objectState) {
const mounted = useRef(true);
const [state, setState] = useState(() => {
if (typeof objectState === 'function') {
objectState = objectState();
}
objectState =
$type(objectState) === OBJECT_TYPE
? Object.assign(Object.create(null), objectState)
: Object.create(null);
return objectState;
});
const setStateMerge = useCallback(
(partialState) => {
if (typeof partialState === 'function') {
partialState = partialState(state);
}
if ($type(partialState) === OBJECT_TYPE) {
partialState = Object.keys(partialState).reduce(
(partialObjectState, key) => {
const value = partialState[key];
return $has(state, key) && !Object.is(state[key], value)
? Object.assign(partialObjectState, { [key]: value })
: partialObjectState;
},
Object.create(null)
);
if (Object.keys(partialState).length > 0 && mounted.current === true) {
setState(Object.assign(Object.create(null), state, partialState));
}
}
},
[state, mounted]
);
useEffect(() => () => {
mounted.current = false;
}, [mounted]);
return [state, setStateMerge];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment