Skip to content

Instantly share code, notes, and snippets.

@ElectricCoffee
Last active October 20, 2022 08:38
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 ElectricCoffee/e68fbc06caa0bb3e10c607d0a179f91d to your computer and use it in GitHub Desktop.
Save ElectricCoffee/e68fbc06caa0bb3e10c607d0a179f91d to your computer and use it in GitHub Desktop.
import { useState } from "react";
/**
* Creates a specialised `useState` which includes mutators in its definition.
* The returned object includes a `get()` method and a `set(x)` method by default.
* @param init The default value
* @param mutators an object containing the mutator functions
* @example
* ```
* const counter = useTilstand(0, {
* inc: (x) => x + 1,
* dec: (x) => x - 1,
* reset: () => 0
* });
*
* // later
* <span>{counter.get()}</span>
* <button onClick={counter.inc}>+</button>
* <button onClick={counter.dec}>-</button>
* ```
*/
export default function useTilstand<
T,
Mut extends { [index: string]: (x: T) => T }
>(init: T, mutators: Mut) {
const [state, setState] = useState(init);
// default accessors
const result = {
get: () => state,
set: (x: T) => setState(x),
};
Object.entries(mutators).forEach(([key, fn]) => {
result[key] = () => setState(fn(state));
})
return result as typeof result & { [K in keyof Mut]: () => T };
}
function Test() {
const counter = useAppState(0, {
inc: (x) => x + 1,
dec: (x) => x - 1,
reset: () => 0,
});
return (
<div>
<h3>{counter.get()}</h3>
<button type="button" onClick={counter.inc}>+</button>
<button type="button" onClick={counter.dec}>-</button>
<button type="button" onClick={counter.reset}>reset</button>
</div>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment