Search code examples
reactjsvue.jsvuejs3micro-frontend

How to use Vue 3 reactive object outside Vue ecosystem


I'm trying to pass global state created like this in micro front end applications. But the problem is that I have to "watch" for changes somehow in order to setState for example in a React app.

globalState.js

import { reactive } from 'vue'

const globalState = reactive({
  counter: 0
})

export default globalState

In Vue micro front ends im doing this and it is working fine

import { createApp } from 'vue'
import App from './App.vue'

export default (rootEl, globalState) => {
  const app = createApp(App)
  app.config.globalProperties.globalState = globalState
  app.mount(rootEl)
}

However in a React app I pass the reference correctly but when counter value changes I have to somehow detect it and call setState in order to rerender the change. The Question is how can I watch for changes of this reactive object reference outside Vue ecosystem.


Solution

  • The Reactivity API is available as standalone libraries (separate from the vue package) that can be used outside the context of Vue.

    @vue/reactivity includes reactive()/ref(). And @vue-reactivity/watch includes watch()/watchEffect().

    For example, you could use a watchEffect (or watch) to log the new value of globalState.counter and display it in an element on the page:

    // main.js
    import { watchEffect } from '@vue-reactivity/watch'
    import globalState from './globalState'
    
    watchEffect(() => {
      console.log('counter', globalState.counter)
      document.querySelector('#count').innerHTML = globalState.counter
    })
    
    // globalState.js
    import { reactive } from '@vue/reactivity'
    
    const globalState = reactive({
      counter: 0
    })
    
    export default globalState
    

    demo 1

    In a React app, you could use a watch to log the new value of globalState.counter and then call a component's setState() to re-render the component:

    import { useState, useEffect } from 'react'
    import { watch } from '@vue-reactivity/watch'
    import globalState from './globalState'
    import GlobalCounterButton from './GlobalCounterButton'
    
    function App() {
      const [count, setCount] = useState(0)
    
      useEffect(() => {
        const unwatch = watch(
          () => globalState.counter,
          (newValue, oldValue) => {
            if (newValue !== oldValue) {
              console.log('counter', newValue)
              setCount(newValue)
            }
          }
        )
        return () => unwatch()
      })
    
      return (
        <div>
          <GlobalCounterButton />
          <h2>count is: {count}</h2>
        </div>
      )
    }
    
    export default App
    

    demo 2