이 글은 주로 vuex의 사용법과 상태 지속 방법에 대한 자세한 설명을 소개하고 참고용으로 올려드립니다.
Vuex는 Vue.js 애플리케이션용으로 특별히 개발된 상태 관리 패턴입니다. 중앙 집중식 스토리지를 사용하여 애플리케이션의 모든 구성 요소 상태를 관리하고 해당 규칙을 사용하여 상태가 예측 가능한 방식으로 변경되도록 합니다.
vuex를 접했을 때 처음으로 본 공식 지침이었습니다.
이 문장에서 다음 정보를 얻을 수 있습니다.
1. vuex는 vue에 대해 존재하는 특수한 Flux입니다. vue가 없으면 vuex를 사용할 수 없습니다. 반대로 redux는 존재하지 않는 것을 볼 수 있는데, vue든 React든 redux를 사용할 수 있다. 따라서 여기에 반영된 vuex의 "기능"은 "보편성"을 갖습니다
2. 중앙 집중식 관리는 vue의 모든 구성 요소의 상태가 vuex
3에 존재함을 나타냅니다. 구성 요소 상태의 변경 사항을 추적할 수 있습니다.
위 그림은 이 기사의 전체 vue 프로젝트 골격의 일부입니다.
vuex는 단일 상태 트리를 사용하며 vue 애플리케이션에는 하나의 상점 인스턴스만 포함됩니다. 따라서 저장소를 vue 인스턴스에 마운트하면 this.$store를 통해 vuex의 다양한 부분을 얻을 수 있습니다.
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를 요청할 때 표시될 로딩 효과를 식별하는 데 사용할 계획입니다. 사용자의 대기심리.
일반적으로 우리 프로젝트에서 가장 많이 사용되는 메소드는 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 })
다중 협업이 필요한 프로젝트에서는 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.js export default { loadingTxt:(state) =>{ return state.isLoading ? '加载中' : '已完成'; } };
export default { loadingTxt:(state) =>{ return state.isLoading ? '加载中' : '已完成'; }, isLoading:(state,getters) => { return 'string' === typeof getters.loadingTxt ? true : false; } };
//组件中 import { mapGetters } from 'vuex' export default { data(){ return { //... } }, computed: { // 使用对象展开运算符将 getter 混入 computed 对象中 ...mapGetters([ 'loadingTxt', 'isLoading', // ... ]) } }
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 }) } ) } }
当我们的项目足够大的时候,单一的状态树这个时候就会显得很臃肿了。因为需要用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 }
用过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里面对应的值。
上面是我整理给大家的,希望今后会对大家有帮助。
相关文章:
在vue 2.x 中使用axios如何封装的get 和post方法
使用node应用中timing-attack存在哪些安全漏洞
위 내용은 vuex와 지속성 사용의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!