Original address: medium.com/better-prog…

Translator:Gavin, prohibit reprinting without authorization.

preface

Vuex is a great state management library that is easy to understand and integrates well with Vue. Why not just use Vuex? The upcoming release of Vue3 exposes the underlying responsive system and introduces a new approach to building applications. New responsive systems are powerful and can be used for shared state management.

Do you need a shared state?

In some cases, data sharing between multiple components is so difficult that centralized state management is required. The situation includes:

  • Multiple components use the same data
  • Multiple root modules require separate access to data
  • Deeply nested components need to communicate data with other components

If none of the above is present, the decision is easy: you don’t need it.

What if that happens? The immediate answer is to use Vuex, a battle-tested solution that works well.

If you don’t want to add another dependency or do too much configuration? Now you can solve these problems with the new Vue3 built-in approach to Composition API.

New solutions

The shared state must meet two criteria:

  • Reactive: When states change, the components that use them update accordingly
  • Availability: Can be accessed from any component

responsive

Vue3 exposes the functions of a reactive system. You can use reactive functions to create a reactive variable (or ref).

import { reactive } from 'vue';

export const state = reactive({ counter: 0 });
Copy the code

The object returned from the reactive function is a Proxy object that listens for changes to its properties. When used in a component template, the component is rerendered whenever the response value changes:

<template>
  <div>{{ state.counter }}</div>
  <button type="button" @click="state.counter++">Increment</button>
</template>

<script>
  import { reactive } from 'vue';
  export default {
    setup() {
      const state = reactive({ counter: 0 });
      return{ state }; }};</script>
Copy the code

availability

The above example works well for a single component, but the multi-component shared state does not. To overcome this problem, you can use Vue3’s provide and inject:

import { reactive, provide, inject } from 'vue';

export const stateSymbol = Symbol('state');
export const createState = () = > reactive({ counter: 0 });

export const useState = () = > inject(stateSymbol);
export const provideState = () = > provide(
  stateSymbol, 
  createState()
);
Copy the code

When you pass Symbol as a key to provide, that value will be made available to any component through the Inject method. Keys are supplied and retrieved using the same Symbol name.

As shown above, if you provide a value on the topmost component, it will be available in all components, or you can call provide on the main file of your application

import { createApp, reactive } from 'vue';
import App from './App.vue';
import { stateSymbol, createState } from './store';

const app = createApp(App);
app.provide(stateSymbol, createState());
app.mount('#app');
Copy the code
<script>
  import { useState } from './state';
  export default {
    setup() {
      return { state: useState() }; }};</script>
Copy the code

More robust solutions

The above scheme has a disadvantage: you don’t know who made the state change, because the state can be changed directly without any restrictions.

You can wrap the state with the readonly function to make it a protected state that needs to be changed by a separate function.

import { reactive, readonly } from 'vue';

export const createStore = () = > {
  const state = reactive({ counter: 0 });
  const increment = () = > state.counter++;

  return { increment, state: readonly(state) };
}
Copy the code

External code can only access the state, and only exported functions can modify the state.

With protected state to avoid unnecessary modifications, the new solution is relatively close to Vuex.

Abstract

By using Vue3’s responsive system and dependency injection mechanism, we have moved from local state management to global state management, and this solution can replace Vuex in small applications.

We have a read-only state object that responds to changes in templates. This state can only be changed in a specific way, like Vuex’s Actions /mutations, which allows you to define other getters using computed functions.