This is the sixth day of my participation in the August Text Challenge.More challenges in August

This article mainly introduces the use of VUex and state persistence in a VUE back-end rendering (SSR) project based on NuxtJS. If you have any inadequacies or suggestions, you are welcome to correct them

The use of vuex

To use vuex in a vUE project, import vuex, then use, and then new vuex.store ({}). In NuxT you don’t need to do this, because when you create a new project, you’ll find that the store directory has been automatically generated in the directory. Just create index.js and start using Vuex, because the nuxt.js kernel implements vuex. In this project, vuEX is used in a modular way officially recommended by NUXT:

Modular definition

As a module, create index.js in the Store directory as the root module and export state, mutations, Actions and getters. Note that in the NUxT project, state needs to be defined as a function and return an object, while the other three are defined as objects directly.

// State needs to be defined as functions
export const state = () = > ({
  tenant: ' '
})
Copy the code

In the store directory, each new.js file is a module. For example, we can create a new user.js file to store the token obtained by the user after logging in:

// store\user.js
export const state = () = > ({
  token: ' '
})

export const mutations = {
  SET_TOKEN: (state, token) = > {
    state.token = token
  }
}

export const actions = {
  // Login with the account and password
  login({ commit }, userInfo) {
    const { username, password } = userInfo
    return new Promise((resolve, reject) = > {
      clientSetting.username = username.trim()
      clientSetting.password = password
      / / callback interface
      this.$api.passport
        .login(clientSetting)
        .then(res= > {
          // The interface returns the token and saves it
          commit('SET_TOKEN', res.access_token)
          resolve(res)
        })
        .catch(error= > {
          reject(error)
        })
    })
  }
}

export const getters = {
  isLogin: state= >!!!!! state.token }Copy the code

If you look in Vue Devtools, you can see that the state defined in the submodule is placed under the user object, with the user/ in front of getters

Used in pages (components)

For example, if you want to trigger SET_TOKEN defined above in store\user.js, you can do this directly:

this.$store.commit('user/SET_TOKEN', res.access_token)
Copy the code

Note that since this is a submodule, the method name is preceded by a user/

Use auxiliary functions

We can also use helper functions to save us some typing. These helper functions return objects, so we can add them directly to computed or methods by deconstructing assignments:

import { mapState } from 'vuex'
computed: {
  ...mapState({
    token: state= > state.user.token
  })
}
Copy the code

Of course, there are also mapGetters, mapMutations and mapActions, which are used in the same way as the general VUE project, so it will not be discussed here.

State persistence

Because the data in VUEX is stored in memory, the data in state will be restored to its original state if the page is refreshed without state persistence. In normal VUE projects, we usually use localStorage, sessionStorage, or cookies for state persistence, so when I decided to use sessionStorage directly in nuxt projects, After a few twists and turns it looks like the code is working fine, but the browser is reporting an error, as shown below:



I guess this may have something to do with the fact that NUxT belongs to a homogeneous framework and cannot be used directly on the server sidewindowThe object’ssessionStorage. There are two solutions in this project, one is to use the package encapsulated by the third party to realize the use of cookies and # WebStorage in NUxT:

1. cookie-universal-nuxt

NPM I cookie-universal-nuxt: NPM I cookie-universal-nuxt:

modules: [ 'cookie-universal-nuxt'].Copy the code

So we can get the $cookies object in the NUxT context. One of the practical applications in this project is state persistence of tokens obtained from the server after login. It can be divided into three parts:

1). Login: Vuex and cookies are synchronized during login. On the login.vue login page, the user fills in the account password and presses the login button, then dispatch the login action written in store\user.js above. This action returns a Promise object that will resolve(res) once the token has been successfully obtained by the login page via the. Then callback and saved to cookies:

handleLogin() {
  this.$store
    .dispatch('user/login'.this.loginForm) // Pass the login form data to vuex for processing
    .then(res= > {
      this.$cookies.set('token', res.access_token) // If the login succeeds, the token is saved to the cookies
      // ...})},Copy the code

2). After strong page flushing, the token stored in VUEX will be initialized back to the initial state. At this time, we can obtain the token through cookies and commit again in the nuxtServerInit unique life cycle of NUXT. Assign the value to the token in state. The nuxtServerInit function is only run once in the server render and can only be defined in the Actions object in the main store template:

// store\index.js
export const actions = {
  nuxtServerInit(store, { app: { $cookies } }) {
    // ...
    // Initialize related data to store in store
    const token = $cookies.get('token') | |' '
    store.commit('user/SET_TOKEN', token)
  }
}
Copy the code

NuxtServerInit takes two arguments. The first is a VUEX context object, which is a store. The second is the NUxT context object, where we can deconstruct the app object and then deconstruct it again to get $cookies.

3). Reading vuex data in AXIos request interception adds a token to the request header, because reading VUex is read from memory and saves performance compared to reading cookies from disk:

// plugins\axios.js
service.onRequest(config= > {
  if (store.state.user.token) {
    config.headers.authorization = 'Bearer ' + store.state.user.token
  }
  // ...
})
Copy the code

2. nuxt-vuex-localstorage

We all know that cookies are submitted each time with the request header. If the information stored in cookies is not needed by the back end, there will undoubtedly be some loss of traffic. In addition, cookies have a size limit of about 4KB. Therefore, another package is used in the project: NuxT-vuex-localStorage, which is used to make state persistence of VUEX data through Web storage:

1). Download and install nuxT-vuex-localStorage

npm i nuxt-vuex-localstorage
Copy the code

2). Configure in nuxt.config.js

modules: [
  // ...
  [
    'nuxt-vuex-localstorage',
    {
      localStorage: ['lsSubmitTranshipOrder']}]],Copy the code

Create lsSubmitTranshiporder.js in the Store directory (the file name is custom) and the state defined in the lsSubmitTranshiporder.js will be stored in localStorage.

3). Create the lsSubmitTranshiporder. js file in the store directory

// store\lsSubmitTranshipOrder.js
export const state = () = > ({
  orderMsg: {
    orderItemId: ' './ / string
    addedServiceFee: [].// Array object
    expire: 12 // The expiration time is 12 hours}})export const mutations = {
  SET_ORDER_ITEM_ID: (state, orderItemId) = > {
    state.orderMsg.orderItemId = orderItemId
  },
  SET_ADDED_SERVICE_FEE: (state, feeObjArr) = > {
    state.orderMsg.addedServiceFee = feeObjArr
  }
}
// ...
Copy the code

Nuxt-vuex-localstorage can also set the expiration time for localstorage through expire.

Now we can use state directly in the page. Even if the page is refreshed, the state defined in store\ lsSubmittranshiporder.js will not be initialized, but will be automatically reevaluated from localStorage. And even when storing non-string data, such as groups or objects, there is no need to convert the data format and use ~ directly