React Context in Vue

What is React Context ?

Context provides a way to pass data through the component tree without having to pass props down manually at every level.

How to use React Context ?

Similar to Redux (Vuex)

graph TB

subgraph Provider
n1[App]
end

n2[View]

subgraph Consumer
n3[Button]
end

subgraph Consumer_
n4[Label]
end

n1-->n2
n2-->n3
n2-->n4

React Context in Vue

provide and inject in Vue option:

  • App

    <script>
    export default {
      name: 'App',
      
      data() {
        return {
          count: 0
        }
      },
      
      provide() {
        const context = {}
        Object.defineProperties(context, {
          count: {
            enumerable: true,
            get() { return this.count },
            set(val) { return this.count = val }
          }
        })
        
        return context
      }
    }
    </script>
    
  • Button

    <script>
    export default {
      name: 'Button',
      
      inject: {
        count: {
          default: 0
        }
      }
      
      methods: {
        // 點擊更新 Button.count, 帶動更新 App.count
      	onClick() {
          this.count++
        }
    	}
    }
    </script>
    
  • Label

    <script>
    export default {
      name: 'Label',
      
      inject: {
        // App.count 更新, 驅動 Label rerender
        count: {
          default: 0
        }
      }
    }
    </script>
    

Wrap it up

Separate Provider's logic from App

  • Provider

    export function provideContext() {
      // create reactive object
      const store = new Vue({
        data() {
          return {
            count: 1
          };
        }
      });
    
      return {
        context: store
      };
    }
    
    export function consumeContext() {
      return {
        context: {
          default: {
            count: 0
          }
        }
      };
    }
    
  • App

    <script>
    import { provideContext } from '/somewhere/Context'
    export default {
      name: 'App',
      
      data() {
        return {
          count: 0
        }
      },
      
      provide: provideContext
    }
    </script>
    
  • Label and Button

    <script>
    import { consumeContext } from '/somewhere/Context'
    export default {
      inject: {
        ...consumeContext()
      }
    }
    </script>
    

When to use

處理需要跨元件的值且:

  1. 更新頻率不高
  2. 非全局環境需要

When to use reactive provide/inject

  1. Do you need to avoid prop drilling? — It can get tedious to pass a prop down through layer after layer of components, especially when those intermediate components don’t actually use the prop. This can also be solved by Vuex, but you sometimes want a simpler and lighter solution
  2. Are the components tightly coupled? — If you have a set of components that will always be used together, then it’s okay to rely on provide/inject to pass some of the data around. Otherwise, it’s best to stick with props and events, which is what most other components will be using
  3. Is Vuex overkill? — Vuex is a great tool, but if you’re dealing with something that has a simple state, then Vuex is overkill and introduces a lot of overhead. If the set of components needs to be reusable, then coupling it with Vuex also introduces unnecessary complexity
  4. Is the data contained within a few components? — If the data being passed around is only used by a couple components, then this solution can make sense. But if the data being used here is used elsewhere, keeping it higher up in the tree or using Vuex can be better solutions

Caution

two-way binding