Skip to content

Instantly share code, notes, and snippets.

@koenbok
Last active November 10, 2023 00:17
Show Gist options
  • Save koenbok/ae7b94f9fefccc16a34589af344db789 to your computer and use it in GitHub Desktop.
Save koenbok/ae7b94f9fefccc16a34589af344db789 to your computer and use it in GitHub Desktop.
import * as React from "react";
/**
A hook to simply use state between components
Warning: this only works with function components (like any hook)
Usage:
// You can put this in an central file and import it too
const useStore = createStore({ count: 0 })
// And this is how you use it from any component
export function Example() {
const [store, setStore] = useStore()
const updateCount = () => setStore({ count: store.count + 1 })
return <div onClick={updateCount}>{store.count}</div>
}
*/
export function createStore<T>(state: T) {
// Store the initial state, copy the object if it's an object
let storeState: T = typeof state === "object" ? { ...state } : state
// Keep a list of all the listener, in the form of React hook setters
const storeSetters = new Set<Function>()
// Create a set function that updates all the listeners / setters
const setStoreState = (state: Partial<T>) => {
// If the state is an object, make sure we copy it
storeState =
typeof state === "object" ? { ...storeState, ...state } : state
// Update all the listeners / setters with the new value
storeSetters.forEach((setter) => setter(storeState))
}
// Create the actual hook based on everything above
function useStore(): [T, typeof setStoreState] {
// Create the hook we are going to use as a listener
const [state, setState] = React.useState(storeState)
// If we unmount the component using this hook, we need to remove the listener
React.useEffect(() => () => storeSetters.delete(setState), [])
// But right now, we need to add the listener
storeSetters.add(setState)
// Return the state and a function to update the central store
return [state, setStoreState]
}
return useStore
}
@jacopocolo
Copy link

jacopocolo commented Oct 20, 2020

@DvDriel first of all you'd want to set up your store and impot like this: https://gist.github.com/koenbok/ae7b94f9fefccc16a34589af344db789#gistcomment-3214773

Then in your components you'd add:
const [store, setStore] = useStore()

This allows you to read the store as a regular variable {store.var}. Or to write a variable with the setStore hook setStore({varName: value}).

The store can contain a single variable or a set of objects.

@koenvanham
Copy link

@koenbok Would this also work in Framer Web? I tried to insert the code but get an error:
image

@koenbok
Copy link
Author

koenbok commented Feb 6, 2021

It seems like TypeScript got a bit stricter with warnings, but it should totally work.

@koenvanham
Copy link

koenvanham commented Feb 8, 2021

Great, got it working indeed. What would be the right way to get this working on a class?

EDIT: nvm, figured out it was preferably to convert old class to a function. got it working now.

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