-
-
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 | |
} |
@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.
@koenbok Would this also work in Framer Web? I tried to insert the code but get an error:
It seems like TypeScript got a bit stricter with warnings, but it should totally work.
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.
@jacopocolo How would the code look like if you use this to share data between two different components that both have their own file? I do not understand where you initialise the store and the value you want to share.
For instance, I have these components:
I want to share a numeric value between the slider and the dial, where do I define the store and where do I initialise this value?
Many thanks in advance!