Skip to content

Instantly share code, notes, and snippets.

@mvolkmann
Created November 18, 2018 19:23
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 mvolkmann/1c5df4124b1d11866fd5dc91969f22a7 to your computer and use it in GitHub Desktop.
Save mvolkmann/1c5df4124b1d11866fd5dc91969f22a7 to your computer and use it in GitHub Desktop.
a custom React hook named "useTopState" that is similar to "useState", but allows multiple components to share the state and be rerendered when it changes
const stateMap = {};
function render(state) {
for (const component of state.components) component.forceUpdate();
}
export default function useTopState(name, initialValue) {
let state = stateMap[name];
if (!state) {
const updater = {
delete() {
this.value = undefined;
render(state);
},
set(value) {
this.value = value;
render(state);
},
transform(fn) {
this.value = fn(this.value);
render(state);
}
};
if (typeof initialValue === 'number') {
updater.decrement = () => {
this.value--;
render(state);
};
updater.increment = () => {
this.value++;
render(state);
};
} else if (Array.isArray(initialValue)) {
updater.filter = fn => {
this.value = this.value.filter(fn);
render(state);
};
updater.map = fn => {
this.value = this.value.map(fn);
render(state);
};
updater.push = (...newValues) => {
this.value.push(...newValues);
render(state);
};
}
state = {components: new Set(), updater, value: initialValue};
stateMap[name] = state;
}
//TODO: Get reference to the component that called this!
const component = 'HOW CAN I GET THIS?';
state.components.add(component);
return [state.value, state.updater];
}
@mvolkmann
Copy link
Author

A function component can use it like this:

export default function MyComponent() {
  const [firstName, firstNameUpdate] = useTopState('firstName', '');
  ...
  // Can change firstName by calling firstNameUpdate.set('Dan').
  // Can uppercase firstName by calling firstNameUpdate.transform(name => name.toUpperCase()).
  // Many components can "watch" the same value of firstName by also calling useTopState('firstName', '').
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment