Skip to content

Instantly share code, notes, and snippets.

@Armster15
Created July 6, 2024 06:39
Show Gist options
  • Save Armster15/94bde205dbb46315cd649fe76005c4b5 to your computer and use it in GitHub Desktop.
Save Armster15/94bde205dbb46315cd649fe76005c4b5 to your computer and use it in GitHub Desktop.
Imperatively update state in React. Based on logic from React Hot Toast
import { useStore, updateState } from './store';
function App() {
const store = useStore();
return (
<div>
<button
onClick={() => {
updateState({
...store,
modals: [...store.modals, Math.random()],
});
}}
>
Click me!
</button>
<pre>{JSON.stringify(store)}</pre>
</div>
);
}
export default App;
// Mostly derived from https://github.com/timolins/react-hot-toast/blob/main/src/core/store.ts
//
// The TLDR of how this works is the component that wants to receive state renders calls the `useStore` hook.
// This hook creates internal React state and stores the setState function in a global `listeners` variable.
// When `updateState`, an imperative function, is called, it iterates through all the listeners (aka setState functions)
// and calls them with the provided state.
//
// As complexity increases, it is recommended to use reducers and actions. See the cited React Hot Toast source file for more info,
// but reducers are simply pure functions that take in the previous state and an action and return the newly updated state.
import { useEffect, useState } from 'react';
interface State {
modals: number[];
}
let listeners: Array<(state: State) => void> = [];
let memoryState: State = { modals: [] };
export function updateState(newState: State) {
memoryState = newState;
for (const listener of listeners) {
listener(memoryState);
}
}
export function useStore(): State {
const [state, setState] = useState<State>(memoryState);
useEffect(() => {
listeners.push(setState);
return () => {
const index = listeners.indexOf(setState);
if (index > -1) {
listeners.splice(index, 1);
}
};
}, [setState]);
return state;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment