Skip to content

Instantly share code, notes, and snippets.

@x1unix
Created December 25, 2021 19:56
Show Gist options
  • Save x1unix/d5b3c6638a567b2befe3ff28ee1b32cb to your computer and use it in GitHub Desktop.
Save x1unix/d5b3c6638a567b2befe3ff28ee1b32cb to your computer and use it in GitHub Desktop.
React - Partial state update
import React from "react";
/**
* Performs partial object update
* @param obj
* @param value
* @param path
*/
export function partialUpdateObject<T=any>(obj: T, value: any, path: string[]): T {
const key = path.pop();
if (!key) {
return obj;
}
if (!path.length) {
return obj ? {...obj, [key]: value} : {[key]: value} as T;
}
const nestedObj = obj[key];
const updatedNestedValue = partialUpdateObject<typeof nestedObj>(nestedObj, value, path);
return { ...obj, [key]: updatedNestedValue};
}
/**
* Partially updates nested state.
*
* @param setter State setter function from `useState`
* @param path Object update path
* @param value New value
*/
export function partialSetState<T>(setter: React.Dispatch<React.SetStateAction<T>>, path: string, value: any) {
const chunks = path.split('.').reverse();
if (chunks.length === 1) {
setter(prev => ({
...prev, [path]: value,
}));
return;
}
setter(prevState => (
partialUpdateObject<T>(prevState, value, chunks)
));
}
/**
* Wraps passed React state dispatcher with partial state setter.
*
* Allows doing partial nested state update for complex objects.
*
* @see partialSetState
* @example
* ```
* const [ value, setValue ] = useState({foo: {bar: 2}});
* const updateValue = usePartialDispatch(setValue);
*
* updateValue('foo.bar', 3);
* ```
* @param dispatch
*/
export function usePartialDispatch<T>(dispatch: React.Dispatch<React.SetStateAction<T | undefined>>) {
return (path: string, value: any) => partialSetState<T | undefined>(dispatch, path, value);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment