vuex와 지속성 사용

亚连
풀어 주다: 2018-06-09 18:04:54
원래의
1853명이 탐색했습니다.

이 글은 주로 vuex의 사용법과 상태 지속 방법에 대한 자세한 설명을 소개하고 참고용으로 올려드립니다.

Vuex는 Vue.js 애플리케이션용으로 특별히 개발된 상태 관리 패턴입니다. 중앙 집중식 스토리지를 사용하여 애플리케이션의 모든 구성 요소 상태를 관리하고 해당 규칙을 사용하여 상태가 예측 가능한 방식으로 변경되도록 합니다.

vuex를 접했을 때 처음으로 본 공식 지침이었습니다.

이 문장에서 다음 정보를 얻을 수 있습니다.

1. vuex는 vue에 대해 존재하는 특수한 Flux입니다. vue가 없으면 vuex를 사용할 수 없습니다. 반대로 redux는 존재하지 않는 것을 볼 수 있는데, vue든 React든 redux를 사용할 수 있다. 따라서 여기에 반영된 vuex의 "기능"은 "보편성"을 갖습니다

2. 중앙 집중식 관리는 vue의 모든 구성 요소의 상태가 vuex

3에 존재함을 나타냅니다. 구성 요소 상태의 변경 사항을 추적할 수 있습니다.

1. 프로젝트에서 vuex 디렉토리 구성

위 그림은 이 기사의 전체 vue 프로젝트 골격의 일부입니다.

vuex는 단일 상태 트리를 사용하며 vue 애플리케이션에는 하나의 상점 인스턴스만 포함됩니다. 따라서 저장소를 vue 인스턴스에 마운트하면 this.$store를 통해 vuex의 다양한 부분을 얻을 수 있습니다.

2.index.js

import vue from 'vue'
import vuex from 'vuex'
import mutations from './mutation'
import getters from './getter'

vue.use(vuex)

const state = {
 isLoading:false
}

export default new vuex.Store({
 state,
 getters,
 mutations
})
로그인 후 복사

인덱스 파일에서 vuex에 저장해야 하는 상태의 초기 값을 정의합니다.

예를 들어 위의 상태 개체에 isLoading 속성을 저장했는데, 이를 완화하기 위해 백엔드 API를 요청할 때 표시될 로딩 효과를 식별하는 데 사용할 계획입니다. 사용자의 대기심리.

3.Mutation(mutation.js)

일반적으로 우리 프로젝트에서 가장 많이 사용되는 메소드는 mutation.js의 메소드입니다. vuex에서 저장소의 상태를 변경하는 유일한 방법은 돌연변이를 제출하는 것입니다.

vuex에서 각 돌연변이에는 문자열 이벤트 유형(mutation-type)과 콜백 함수(handler)가 있습니다.

이 콜백 함수는 두 개의 매개변수를 받을 수 있습니다. 첫 번째 매개변수는 상태이고 두 번째 매개변수는 변이의 페이로드입니다.

//...
mutations: {
 /**
 * @method:只传入state,修改loading状态
 * @param {bool} isLoading:loading状态
 */ 
 changeLoading(state) {
 state.isLoading = !state.isLoading
 }
}
store.commit('changeLoading')

mutations: {
 /**
 * @method:传入state和payload,修改loading状态
 * @param {bool} isLoading:loading状态
 */ 
 changeLoading(state,payload) {
 state.isLoading = payload.isLoading
 }
}
store.commit('changeLoading',{isLoading: true})
로그인 후 복사

변형을 제출하는 또 다른 방법은 type 속성이 포함된 객체를 직접 사용하는 것입니다. 하지만 이 방법은 별로 권장하지 않습니다. 위의 방식으로 처리하면 코드가 더 읽기 쉬워지기 때문입니다.

store.commit({
 type: 'changeLoading',
 isLoading: true
})
로그인 후 복사

4.mutation-types.js

다중 협업이 필요한 프로젝트에서는 mutation 이벤트 유형 대신 상수를 사용할 수 있습니다. 이는 다양한 Flux 구현에서 매우 일반적인 패턴입니다. 또한 이러한 상수를 별도의 파일에 유지하면 공동 개발이 명확해집니다.

// mutation-types.js
export const CHANGE_LOADING= 'CHANGE_LOADING'

// mutation.js
import { CHANGE_LOADING} from './mutation-types'

export default{
 [CHANGE_LOADING](state,payload){
  state.isLoading = payload.isLoading
 },
}
로그인 후 복사

Mutation 유형의 이벤트 유형을 정의할 때 제가 직접 정의한 사양은 대략 다음과 같습니다.

1. Mutation은 이벤트와 유사하므로 동사로 시작합니다

2 단어는 밑줄로 연결됩니다.

3 , vuex에 저장된 상태는 RECORD로 표시됩니다

4. 로컬로 캐시된 상태는 SAVE로 표시됩니다

물론, 돌연변이를 통해 돌연변이의 의도를 알 수 있는 한 이 사양을 직접 정의할 수 있습니다. 유형, 그것은 훌륭합니다.

5. Getter(getter.js)

때로는 저장소의 상태에서 일부 상태를 파생해야 합니다. 예를 들어 위에서 언급한 것처럼 비동기 요청 중에 마스크 레이어를 사용하여 로딩을 표시해야 합니다. 내 로딩 중 상태에 따라 로딩 상태를 표시해야 합니다. getter를 사용하지 않고 계산된 속성을 사용하여 처리하도록 선택합니다.

computed: {
 loadingTxt () {
 return this.$store.state.isLoading ? '加载中' : '已完成';
 }
}
로그인 후 복사

하지만 우리의 로딩은 많은 컴포넌트에서 사용되어야 합니다. 그런 다음 함수를 복사하거나 공유 함수로 추출하여 여러 위치에서 가져와야 합니다. 어느 쪽도 이상적이지 않습니다.

Getter를 사용하면 모든 것이 아름다워집니다.

//getter.js
export default {
 loadingTxt:(state) =>{
  return state.isLoading ? '加载中' : '已完成';
 } 
};
로그인 후 복사

계산된 속성과 마찬가지로 getter의 반환 값은 종속성에 따라 캐시되며 종속성 값이 변경될 때만 다시 계산됩니다.

또한 Getter는 두 번째 매개변수로 다른 게터를 허용할 수도 있습니다.

export default {
 loadingTxt:(state) =>{
  return state.isLoading ? '加载中' : '已完成';
 },
  isLoading:(state,getters) => {
  return 'string' === typeof getters.loadingTxt ? true : false;
 } 
};
로그인 후 복사

스토어의 게터는 mapGetters 보조 함수

//组件中
import { mapGetters } from 'vuex'

export default {
 data(){
 return {
  //...
 }
 },
 computed: {
 // 使用对象展开运算符将 getter 混入 computed 对象中
 ...mapGetters([
  'loadingTxt',
  'isLoading',
  // ...
 ])
 }
}
로그인 후 복사

6.Action(action.js)

함수를 통해 로컬 계산 속성에 매핑될 수 있습니다. action mutation과 비슷하지만, action과 mutation 사이에는 두 가지 차이점이 있습니다.

1. Action은 주로 비동기 작업을 처리하지만, action에는 이러한 제한이 적용되지 않습니다. 즉, 액션에서 동기 및 비동기 작업을 모두 처리할 수 있습니다.

2. 액션은 상태를 변경하고 최종적으로 돌연변이를 제출합니다.

장바구니를 예로 들어 제품을 추가하면 먼저 SKU와 관련된 백엔드와 통신해야 하거나 사용자가 SKU를 추가했지만 주문하지 않은 경우.

배경 추가가 성공하면 프런트엔드에 새로 추가된 제품이 표시됩니다. 실패하면 사용자에게 추가가 실패했음을 알려야 합니다.

const actions = {
 checkout ({ 
   state,
      commit,
   //rootState 
      }, products) {
 const savedCartItems = [...state.added]
 commit(SET_CHECKOUT_STATUS, null)
 // 置空购物车
 commit(SET_CART_ITEMS, { items: [] })
 shop.buyProducts(
  products,
   //成功
  () => commit(SET_CHECKOUT_STATUS, 'successful'),
  //失败
  () => {
  commit(SET_CHECKOUT_STATUS, 'failed')
  commit(SET_CART_ITEMS, { items: savedCartItems })
  }
 )
 }
}
로그인 후 복사

7.module

当我们的项目足够大的时候,单一的状态树这个时候就会显得很臃肿了。因为需要用vuex进行状态管理的状态全部集中在一个state对象里面。

所以,当一个东西大了以后,我们就要想办法进行分割,同样的道理,我们熟知的分冶法和分布式其实也是基于这样的一个思想在里面。而vuex提供了module,我们就可以去横向的分割我们的store。

比如说,我在项目中需要去做一个购物车这样的东西,这在电商的项目中也是常见的需求。

//shopCart.js
import shop from '../../api/shop'
import {
 ADD_TO_CART,
 SET_CART_ITEMS,
 SET_CHECKOUT_STATUS
} from '../mutation-types'

const state = {
 added: [],
 checkoutStatus: null
}

/**
 * module getters
 * @param {Object} state:模块局部state
 * @param {Object} getters:模块局部getters,会暴露到全局
 * @param {Object} rootState:全局(根)state
 */
const getters = {
 checkoutStatus: state => state.checkoutStatus,
 cartProducts: (state, getters, rootState) => {
 return state.added.map(({ id, quantity }) => {
  const product = rootState.products.all.find(product => product.id === id)
  return {
  title: product.title,
  price: product.price,
  quantity
  }
 })
 },
 cartTotalPrice: (state, getters) => {
 return getters.cartProducts.reduce((total, product) => {
  return total + product.price * product.quantity
 }, 0)
 }
}

/**
 * module actions
 * @param {Object} state:模块局部state
 * @param {Object} getters:模块局部getters,会暴露到全局
 * @param {Object} rootState:全局(根)state
 */
const actions = {
 checkout ({ 
   state,
      commit,
   //rootState 
      }, products) {
 const savedCartItems = [...state.added]
 commit(SET_CHECKOUT_STATUS, null)
 // 置空购物车
 commit(SET_CART_ITEMS, { items: [] })
 shop.buyProducts(
  products,
   //成功
  () => commit(SET_CHECKOUT_STATUS, 'successful'),
  //失败
  () => {
  commit(SET_CHECKOUT_STATUS, 'failed')
  commit(SET_CART_ITEMS, { items: savedCartItems })
  }
 )
 }
}

/**
 * module mutations
 * @param {Object} state:模块局部state
 * @param payload:mutation的载荷
 */
const mutations = {
 //用id去查找商品是否已存在,
 [ADD_TO_CART] (state, { id }) {
 state.checkoutStatus = null
 const record = state.added.find(product => product.id === id)
 if (!record) {
  state.added.push({
  id,
  quantity: 1
  })
 } else {
  record.quantity++
 }
 },
 [SET_CART_ITEMS] (state, { items }) {
 state.added = items
 },
 [SET_CHECKOUT_STATUS] (state, status) {
 state.checkoutStatus = status
 }
}

export default {
 state,
 getters,
 actions,
 mutations
}
로그인 후 복사

在module的定义的局部state,getters,mutation,action中,后三个都会暴露到全局的store中去,这样使得多个模块能够对同一 mutation 或 action 作出响应。就不需要在其他的模块中去定义相同的mutation或action了。

而这里的state是局部的。这也导致后来的持久化无法去处理用module分割后的state。

如同上面的module =》shopCart,

当我们无论是在index.js里面或者其他的module中,shopCart里面的getters或者action或者mutations,我们都可以去使用。

//test.js
const state = {
 isTest:false
};

const getters = {
 isTest :state => state.isTest,
 checkTestStatus:(state,getters) => {
 return getters.checkoutStatus;
 }
};

export default {
 state,
 getters,
}
//组件中
...mapGetters([
 'checkTestStatus'
])
//...
created(){
 this.checkTestStatus ;//null
}
로그인 후 복사

如果说,我就想让我的module里面的定义的全部都是独享的。我们可以使用module的命名空间,通过设置namespaced: true。

//test.js
const getters = {
 // 在这个模块的 getter 中,`getters` 被局部化了
 // 你可以使用 getter 的第四个参数来调用 `rootGetters`
 someGetter (state, getters, rootState, rootGetters) {
 getters.someOtherGetter // 'test/someOtherGetter'
 rootGetters.someOtherGetter // 'someOtherGetter'
 },
 someOtherGetter: state => { ... }
};

const actions = {
 // 在这个模块中, dispatch 和 commit 也被局部化了
 // 他们可以接受 `root` 属性以访问根 dispatch 或 commit
 someAction ({ dispatch, commit, getters, rootGetters }) {
 getters.someGetter // 'test/someGetter'
 rootGetters.someGetter // 'someGetter'

 dispatch('someOtherAction') // 'test/someOtherAction'
 dispatch('someOtherAction', null, { root: true }) // 'someOtherAction'

 commit('someMutation') // 'test/someMutation'
 commit('someMutation', null, { root: true }) // 'someMutation'
 },
 someOtherAction ({ state,commit }, payload) { ... }
}

export default {
 namespaced: true,
 state,
 getters,
 actions,
 mutations
}
로그인 후 복사

8.持久化state的工具:vuex-persistedstate

用过vuex的肯定会有这样一个痛点,就是刷新以后vuex里面存储的state就会被浏览器释放掉,因为我们的state都是存储在内存中的。

而像登录状态这样的东西,你不可能一刷新就让用户重新去登录吧!所以,我们会去选择把状态存储到本地。

这样一来问题貌似是解决了,但是当我们需要使用的时候,我们就需要不断的从本地,通过getStore这样的方法去取得我们state。如果需要更新的话,我们又要在mutation里面通过setStore这样的方法去处理它。

虽然,我们的setStore都是在操作了state以后再去调用的,也就是说无论是通过vuex的logger或者vue的dev tool我们都是可以对local里面的状态进行跟踪的,但是,我们无法保证我们每次都记着去写setStore。

这样一来,在共享state的组件中,我们的代码可能就会是这样的。

import { getStore } from '@/util'
//组件中
mounted(){
 this.foo = getStore('foo');
 this.bar = getStore('bar');
 //.... 
}
로그인 후 복사

那么,如何去改进呢?

我们能想到的就是,能不能让state不是保存在内存中,而是存储在本地。

而vuex-persistedstate做了这样的事情,它帮我们将store里面的state映射到了本地环境中。这样一来,我通过提交mutation改变的state,会动态的去更新local里面对应的值。

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

在bootstrap中如何实现table支持高度百分比

在vue 2.x 中使用axios如何封装的get 和post方法

使用node应用中timing-attack存在哪些安全漏洞

在vue组件传递对象中实现单向绑定,该怎么做?

위 내용은 vuex와 지속성 사용의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿