There exist a million (or many) global state solutions in React. It seems like the community is struggling to find the best solution. So here I'm going to come with yet another one.
Recently Vue 3 was released. I know, Vue is another framework, but Vue solves the reactivity in a way that it's not tied to the framework. Which means we can use the reactivity everywhere, including React.
First, let's create a store file.
store.js
import { reactive } from 'vue'
const store = reactive({
count: 0
})
const increase = () => store.count++
export { store, increase }
For an overview of what the Vue composition API can do except for reactive
you can get an overview here.
Now we can import the reactive store
object and the increase
method from the store.js file anywhere we like to. The problem is that React functions don't know when to re-run the function to render the updated values. We will create a custom hook to deal with this.
useStore.js
import { useReducer, useEffect } from 'react'
import { watch } from 'vue'
function useStore(...stores) {
const [ignored, forceUpdate] = useReducer(x => x + 1, 0)
useEffect(() => {
const stopWatch = watch(stores, forceUpdate)
return stopWatch
}, [])
}
export default useStore;
We can either use useState
or useReducer
to make the component update itself. We are watching the params stores
with the Vue Composition API and calls forceUpdate
on every change. Also, we stop watching on component unmount by returning stopWatch
in useEffect
. Any amount of stores could be passed into our useStore
.
Bump.js
import React from "react";
import { increase } from './store'
export default function Bump() {
return (
<button onClick={increase}>+1</button>
);
}
We could also do store.count++
directly here if we wanted.
Counter.js
import React from "react";
import { store } from './store'
import useStore from './useStore'
export default function Counter() {
useStore(store)
return (
<p>{store.count}</p>
);
}
Complete example on StackBlitz
Afterthoughts
I actually think this is a nice and simple way of handling a global state. No need for extra components, reduce, dispatch, and/or complete re-assigning of the whole state object. This way we can create exactly as many global stores as we want in a clean way.
Importing the whole Vue might create a bigger bundle size. But you can import only Vue's reactivity module @vue/reactivity and @vue-reactivity/watch or rely on tree shaking for a small bundle.
Now not every developer would want a different way of dealing with component state and global state, so the React way and Vue way might be confusing in the same project. But it's at least an interesting and fun idea.
Top comments (13)
So ingenious! Thanks for sharing!
4.7kB combined min/gzipped isn't the tiniest, but it's far from terrible. Nice job.
Now the question is, is it CM-compatible?
@dai_shi is the authority when it comes to this AFAIK.
Vue 3 is also modularized and takes advantage of tree shaking what means the final bundle could be much smaller :)
For example, we could use only @vue/reactivity package for some cases :D
youtu.be/Vp5ANvd88x0?t=1515
I was referring to the Bundlephobia sizes for @vue/reactivity (3.7kB min/gzipped) and @vue-reactivity/watch (929B min/gzipped).
Just an observation. Still a great way to think outside the box, and I meant in no way to take away from your post. That size is in line with some of the better React state management options.
FWIW I think RxDB (which is a comparatively massive bundle no matter what you tree shake and exclude, due to RxJS and currently PouchDB dependencies) is a fantastic state management solution for React.
Oh, I really missed afterthoughts, you right.
Still nice to see coming unification between js frameworks, like vue composition api alternative to react hooks or new Vue SFC components which are very similar to svelte components
Nice! Thanks for sharing
I'm not convinced, plus I see some possible performance implications with this.
I'd still use Recoil.js for React.
Probably a good choice. I wasn't really trying to convince anyone, just playing with the idea :)
Nice post there, Gaute.
It indeed is an interesting and fun idea. Folks can probably derive from this example and mix and match between frameworks/libraries :)
Amazing!!
Thanks for sharing
Haha, react devs must be unhappy !
"More competition in the state management space is a good thing for innovation." -- me, a React dev