[Vuex state management] Basic use of Vuex; basic use of core concepts State, Getters, Mutations, Actions, Modules

1_Application state management

1.1_State Management

During development, the application needs to process a variety of data, which needs to be stored in a certain location in the application, and the management of these data is called state management.

How to manage your own state in the front?

  • In Vue development, use a componentized development method;
  • And define data in the component or return the data used in the setup, these data are called state;
  • These data can be used in the module template, and the module will eventually be rendered into DOM, which is called View;
  • Some behavioral events will be generated in the module. When processing these behavioral events, the state may be modified. These behavioral events are called actions;

1.2_ complex state management

Applications developed in JavaScript have become more and more complex:

  • JavaScript needs to manage more and more states and more and more complex;
  • These states include data returned by the server, cached data, data generated by user operations, etc.;
  • It also includes some UI status, such as whether certain elements are selected, whether to display loading animation, and current page;

The simplicity of unidirectional data flow is easily broken when your application encounters multiple components sharing state:

  • Multiple views depend on the same state;
  • Actions from different views need to mutate the same state;

Can it be done by passing component data?

  • For some simple states, it is indeed possible to share the state through the transfer of props or Provide;
  • But for complex state management, it is obviously not enough to solve the problem simply by passing and sharing. For example, how do sibling components share data?

1.3_Vuex state management

Managing the changing state itself is very difficult:

  • There will be dependencies between states, a state change will cause another state change, and the View page may also cause state changes;
  • When the application is complex, when, for what reason, and how the state changes, it will become very difficult to control and track;

Therefore, is it possible to consider extracting the internal state of the component and managing it as a global singleton?

  • In this mode, the component tree constitutes a huge "view";
  • No matter where in the tree, any component can get state or trigger behavior;
  • By defining and isolating the various concepts in state management, and maintaining the independence between views and states through mandatory rules, the code side will become more structured and easy to maintain and track;

This is the basic idea behind Vuex, which borrows from Flux, Redux, and Elm (pure functional language, redux has its ideas for reference);
Vue officials are also recommending the use of Pinia for state management, follow-up learning


Refer to the picture on the official website
insert image description here


Basic use of 2_Vuex

2.1_installation

npm install


2.2_Create Store

The core of every Vuex application is store (warehouse): store is essentially a container that contains most of the state in the application;

What's the difference between Vuex and a plain global object?

  • First: Vuex's state store is responsive. When the Vue component reads the state from the store, if the state in the store changes, the corresponding component will also be updated;

  • Second: You cannot directly change the state in the store.

    • The only way to change the state in the store is to commit the mutation explicitly;
    • This makes it easy to track each state change, so that some tools can help better manage the state of the application;

demo:

(1) Under the src folder, create a new folder store. Under this folder, the index.js file is generally created, or it can be created according to actual development.

src/store/index.js

import {
    
     createStore } from 'vuex'

const store = createStore({
    
    
  state: () => ({
    
    
    counter: 100
  })
})  

(2) Register in main.js

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

createApp(App).use(store).mount('#app')

(3) Called in App.vue

<template>
  <div class="app">
    <!-- store中的counter -->
    <h2>App当前计数: {
    
    {
    
     $store.state.counter }}</h2>
  </div>
</template>

2.3_ Use store in components

Use the store in the component, as follows:

  • Used in the template tempte, such as the 2.2 demo
  • Used in the options api, such as computed;
  • Used in setup;
<template>
  <div class="app">
      <!-- 在模板tempte中使用store -->
    <h2>Home当前计数: {
   
   { $store.state.counter }}</h2>
    <h2>Computed当前计数: {
   
   { storeCounter }}</h2>
    <h2>Setup当前计数: {
   
   { counter }}</h2>
    <button @click="increment">+1</button>
  </div>
</template>

<script>
  export default {
      
      
      //在options api中使用,比如computed;
    computed: {
      
      
      storeCounter() {
      
      
        return this.$store.state.counter
      }
    }
  }
</script>

<!-- 在setup中使用store -->
<script setup>
  import {
      
       toRefs } from 'vue'
  import {
      
       useStore } from 'vuex'

  const store = useStore()
  const {
      
       counter } = toRefs(store.state)
  
  function increment() {
      
      
    store.commit("increment")
  }
</script>

3_Core concept State

3.1_Single state tree

Vuex uses a single state tree:

  • Use one object to contain all application-level state;
  • SSOT, Single Source of Truth is used, which can also be translated into a single data source;

This also means that each application will only contain one store instance, single-state tree and modularization do not conflict, and the concept of module will be involved later;

Advantages of a single state tree:

  • If the state information is stored in multiple Store objects, subsequent management and maintenance will become particularly difficult;
  • So Vuex also uses a single state tree to manage all states at the application level;
  • A single state tree allows the most direct way to find a fragment of a state;
  • And in the subsequent maintenance and debugging process, it can also be very convenient to manage and maintain;

3.2_Component get state

In the previous demo, we know how to get the state in the component.

Of course, if you feel that way is a bit cumbersome (the expression is too long), you can use computed properties:

    computed: {
    
    
      storeCounter() {
    
    
        return this.$store.state.counter
      }
    }

However, if there are many states that need to be obtained, mapStatethe helper function that can be used:

  • Method 1 of mapState: object type;
  • The second method of mapState: array type;
  • You can also use the spread operator to mix with the original computed;

3.3_Using mapState in setup

It is very simple to obtain a single state in the setup, just get a certain state after getting the store through useStore.

But if you use mapState how to get the state?

(1) By default, Vuex does not provide a very convenient way to use mapState, the following method is not recommended

<template>
  <div class="app">
    <!-- 在模板中直接使用多个状态 -->
    <h2>name: {
   
   { $store.state.name }}</h2>
    <h2>level: {
   
   { $store.state.level }}</h2>
    <h2>avatar: {
   
   { $store.state.avatarURL }}</h2>
  </div>
</template>

<script setup>
  import {
      
       computed } from 'vue'
  import {
      
       mapState, useStore } from 'vuex'

  // 一步步完成,步骤繁琐
  const {
      
       name, level } = mapState(["name", "level"])
  const store = useStore()
  const cName = computed(name.bind({
      
       $store: store }))
  const cLevel = computed(level.bind({
      
       $store: store }))
</script>

(2) A function package is performed here to simplify the steps

src/hooks/useState.js

import {
    
     computed } from 'vue'
import {
    
     useStore, mapState } from 'vuex'

export default function useState(mapper) {
    
    
  const store = useStore()
  const stateFnsObj = mapState(mapper)
  
  const newState = {
    
    }
  Object.keys(stateFnsObj).forEach(key => {
    
    
    newState[key] = computed(stateFnsObj[key].bind({
    
     $store: store }))
  })

  return newState
}

use the function

<template>
  <div class="app">
    <!-- 在模板中直接使用多个状态 -->
    <h2>name: {
    
    {
    
     $store.state.name }}</h2>
    <h2>level: {
    
    {
    
     $store.state.level }}</h2>
    <h2>avatar: {
    
    {
    
     $store.state.avatarURL }}</h2>
  </div>
</template>

<script setup>
  import useState from "../hooks/useState"
  // 使用useState封装函数
  const {
    
     name, level } = useState(["name", "level"])
</script>

(3) It is more recommended to use the following methods

<template>
  <div class="app">
    <!-- 在模板中直接使用多个状态 -->
    <h2>name: {
   
   { $store.state.name }}</h2>
    <h2>level: {
   
   { $store.state.level }}</h2>
    <h2>avatar: {
   
   { $store.state.avatarURL }}</h2>
  </div>
</template>

<script setup>
  import {
      
       computed, toRefs } from 'vue'
  import {
      
       mapState, useStore } from 'vuex'

  // 3.直接对store.state进行解构(推荐)
  const store = useStore()
  const {
      
       name, level } = toRefs(store.state)
</script>

4_Core concept Getters

4.1 Basic use of _getters

Some properties may need to be used after changes, and getters can be used at this time

insert image description here


4.2_getters second parameter

getters can accept a second parameter

  getters: {
    
    
    // 2.在该getters属性中, 获取其他的getters
    message(state, getters) {
    
    
      return `name:${
      
      state.name} level:${
      
      state.level} friendTotalAge:${
      
      getters.totalAge}`
    }

  }

4.3 Return function of _getters

  getters: {
    
    
    // 3.getters是可以返回一个函数的, 调用这个函数可以传入参数(了解)
    getFriendById(state) {
    
    
      return function(id) {
    
    
        const friend = state.friends.find(item => item.id === id)
        return friend
      }
    }
  }

4.4 Auxiliary functions of_mapGetters

A helper function that can use mapGetters

<template>
  <div class="app">
    <h2>doubleCounter: {
   
   { doubleCounter }}</h2>
    <h2>friendsTotalAge: {
   
   { totalAge }}</h2>
    <!-- 根据id获取某一个朋友的信息 -->
    <h2>id-111的朋友信息: {
   
   { getFriendById(111) }}</h2>
    <h2>id-112的朋友信息: {
   
   { getFriendById(112) }}</h2>
  </div>
</template>

<script>
  import {
      
       mapGetters } from 'vuex'

  export default {
      
      
    computed: {
      
      
      ...mapGetters(["doubleCounter", "totalAge"]),
      ...mapGetters(["getFriendById"])
    }
  }
</script>

Can also be used in setup

<template>
  <div class="app">
    <h2>message: {
   
   { message }}</h2>
  </div>
</template>

<script setup>
  import {
      
       computed, toRefs } from 'vue';
  import {
      
       mapGetters, useStore } from 'vuex'

  const store = useStore()

  // 1.使用mapGetters ,较麻烦
  // const { message: messageFn } = mapGetters(["message"])
  // const message = computed(messageFn.bind({ $store: store }))

  // 2.直接解构, 并且包裹成ref
  // const { message } = toRefs(store.getters)

  // 3.针对某一个getters属性使用computed
  const message = computed(() => store.getters.message)
</script>

5_Core concept Mutations

The only way to change the state in Vuex's store is to submit a mutation

5.1_Use

When submitting a mutation, some data will be carried. At this time, parameters can be used. Note that the payload is an object type

mutation :{
    
    
 add(state,payload){
    
    
   statte.counter + = payload
 }
}

submit

$store.commit({
    
    
  type: "add",
  count: 100
})

5.2_Mutation constant type

demo:

(1) In mutation-type.js, define constants

export const CHANGE_INFO = "changeInfo"

(2) Use constants in store

  mutations: {
    
    
      [CHANGE_INFO](state, newInfo) {
    
    
      state.level = newInfo.level
      state.name = newInfo.name
    }
  }

(3) in use
insert image description here


5.3 Important principles of mutation

An important principle is that mutation must be a synchronous function

  • This is because the devtool tool will record the mutation log;
  • Every mutation is recorded, and devtools needs to capture a snapshot of the previous state and the next state;
  • However, when asynchronous operations are performed in mutation, data changes cannot be tracked;

6_Core concept Actions

6.1_Basic use

Action is similar to mutation, the difference is:

  • Action submits mutation instead of directly changing state;

  • Action can contain any asynchronous operation;

There is a very important parameter context:

  • context is a context object with the same methods and properties as the store instance;
  • So you can get the commit method from it to submit a mutation, or get state and getters through context.state and context.getters;

For specific cases, refer to this article : https://blog.csdn.net/qq_21980517/article/details/103398686


6.2_Distribution operation

insert image description here


6.3 Asynchronous operation of_actions

Actions are usually asynchronous. You can know when the action ends by letting the action return a Promise, and then handle the completed operation in the then of the Promise.

demo:

In index.js, take sending a network request as an example

action{
    
    
	fetchHomeMultidataAction(context) {
    
    
      // 1.返回Promise, 给Promise设置then
      // fetch("http://123.207.32.32:8000/home/multidata").then(res => {
    
    
      //   res.json().then(data => {
    
    
      //     console.log(data)
      //   })
      // })
      
      // 2.Promise链式调用
      // fetch("http://123.207.32.32:8000/home/multidata").then(res => {
    
    
      //   return res.json()
      // }).then(data => {
    
    
      //   console.log(data)
      // })
      return new Promise(async (resolve, reject) => {
    
    
        // 3.await/async
        const res = await fetch("http://123.207.32.32:8000/home/multidata")
        const data = await res.json()
        
        // 修改state数据
        context.commit("changeBanners", data.data.banner.list)
        context.commit("changeRecommends", data.data.recommend.list)

        resolve("aaaaa")
      })
    }
 }   

in test3.vue

<script setup>
  import {
    
     useStore } from 'vuex'
  // 告诉Vuex发起网络请求
  const store = useStore()
  store.dispatch("fetchHomeMultidataAction").then(res => {
    
    
    console.log("home中的then被回调:", res)
  })

</script>



7_ Core concept Modules

7.1 Basic use of_module

Module understanding?

  • Due to the use of a single state tree, all the states of the application will be concentrated into a relatively large object. When the application becomes very complex, the store object may become quite bloated;
  • In order to solve the above problems, Vuex allows the store to be divided into modules (module);
  • Each module has its own state, mutation, action, getter, and even nested submodules
    insert image description here

7.2 Local state of_module

For mutations and getters inside a module, the first parameter received is the module's local state object
insert image description here


7.3 Namespace of_module

By default, actions and mutations within a module are still registered in the global namespace:

  • This enables multiple modules to respond to the same action or mutation;
  • Getters are also registered in the global namespace by default;

If you want the module to have a higher degree of encapsulation and reusability, you can add namespaced: true to make it a module with a namespace. When the module is registered, all its getters, actions and mutations will be automatically adjusted according to the path registered by the module name

demo:counter,js

const counter = {
    
    
  namespaced: true, //命令空间
  state: () => ({
    
    
    count: 99
  }),
  mutations: {
    
    
    incrementCount(state) {
    
    
      console.log(state)
      state.count++
    }
  },
  getters: {
    
    
    doubleCount(state, getters, rootState) {
    
    
      return state.count + rootState.rootCounter
    }
  },
  actions: {
    
    
    incrementCountAction(context) {
    
    
      context.commit("incrementCount")
    }
  }
}

export default counter

7.4_module modify or distribute root components

Modify the state in the root in the action, then there are the following ways
insert image description here

Guess you like

Origin blog.csdn.net/qq_54075517/article/details/132574963