Vuex는 Vue.js 애플리케이션용으로 특별히 개발된 상태 관리 모델로, 애플리케이션의 모든 구성 요소 상태를 중앙에서 저장하고 관리합니다. 이 글은 Vuex 사용법 문서를 모두에게 소개합니다. 필요한 친구들은 참고할 수 있습니다
Vuex란 무엇인가요?
Vuex는 Vue.js 애플리케이션용으로 특별히 개발된 상태 관리 패턴입니다. 중앙 집중식 스토리지를 사용하여 애플리케이션의 모든 구성 요소 상태를 관리하고 해당 규칙을 사용하여 상태가 예측 가능한 방식으로 변경되도록 합니다. Vuex는 Vue의 공식 디버깅 도구 devtools 확장에도 통합되어 제로 구성 시간 이동 디버깅, 상태 스냅샷 가져오기 및 내보내기 등과 같은 고급 디버깅 기능을 제공합니다.
설치
직접 다운로드 CDN 참조
<script src="/path/to/vue.js"></script> <script src="/path/to/vuex.js"></script>
npm
npm install vuex --save
모듈형 패키징 시스템에서는 Vue.use()를 통해 명시적으로 Vuex를 설치해야 합니다.
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex)
Vuex는 Vue.js 애플리케이션용으로 특별히 개발된 상태 관리 모델로, 애플리케이션의 모든 구성 요소 상태를 중앙에서 저장하고 관리합니다.
상태 관리에는 다음과 같은 부분 상태가 포함됩니다.
상태는 애플리케이션의 데이터 소스를 구동합니다.
View는 실제와 같은 방식으로 상태를 뷰에 매핑합니다.
액션은 뷰에 대한 사용자 입력으로 인한 상태 변경에 응답합니다.
중대형 단일 페이지 애플리케이션의 공유 상태를 관리할 수 있도록 도와주세요.
state
단일 상태 트리, Vuex는 단일 상태 트리를 사용하여 하나의 개체에 모든 애플리케이션 수준 상태를 포함합니다.
Vue 구성 요소에서 Vuex 상태를 가져옵니다.
Vuex의 상태 저장소는 반응형이므로 저장소 인스턴스에서 상태를 읽는 가장 쉬운 방법
은 계산된 속성에서 특정 상태를 반환하는 것입니다.
카운터 컴포넌트 생성
const Counter = { template: '<p>{{ count }}</p>' computed: { count (){ return store.state.count } } }
store.state.count가 변경될 때마다 계산된 속성이 다시 계산되고 관련 DOM의 업데이트가 트리거됩니다.
Vuex는 루트 컴포넌트에서 상태를 전송하는 메커니즘을 제공합니다. 각 하위 구성 요소에 저장소 옵션 "주입"을 통해(Vue.use(Vuex)를 호출해야 함):
const app = new Vue({ el:'#app', // 把 store 对象提供给 “store” 选项,这可以把 store 的实例注入所 有的子组件 store, components: {Counter}, template: ' <p class="app"> <counter></counter> </p> ' })
루트 인스턴스에 저장소 옵션을 등록하면 저장소 인스턴스가 모든 하위 구성 요소에 등록됩니다. 컴포넌트 아래의 컴포넌트와 하위 컴포넌트는 this.$store를 통해 접근할 수 있습니다. 카운터 구현 업데이트:
const Counter = { template : '<p>{{ count }}</p>', computed: { count this.$store.state.count } }
mapState 도우미 함수
구성 요소가 여러 상태를 얻어야 하는 경우 이러한 상태를 계산된 속성으로 선언하는 것은 중복됩니다.
이 문제를 해결하려면 mapState 도우미 함수를 사용하여 계산된 속성을 생성할 수 있습니다.
// 在单独构建的版本中辅助函数为 Vuex.mapState import { mapState } from 'vuex' export default { computed: mapState({ // 箭头函数可以使代码更简洁 count: state => state.count, // 传字符串参数 ‘count' 等同于 ‘state => state.count' countAlias: 'count', // 为了能够使用 ‘this' 获取局部状态,必须使用常规函数 countPlusLocalState(state) { return state.count + this.localCount } }) }
매핑된 계산 속성의 이름이 상태의 하위 노드 이름과 동일한 경우 문자열 배열을 mapState에 전달할 수도 있습니다.
computed: mapState([ // 映射 this.count 为 store.state.count 'count' ])
구성 요소는 여전히 로컬 상태를 유지합니다.
Getters
때로는 목록 필터링 및 계산과 같이 저장소의 상태에서 일부 상태를 파생해야 할 때도 있습니다.
computed: { doneTodosCount() { return this.$store.state.todos.filter(todo => todo.done).length } }
Vuex를 사용하면 저장소에서 getter를 정의할 수 있습니다(저장소의 계산된 속성으로 생각할 수 있음)
Getter는 상태를 첫 번째 매개변수로 받아들입니다.
const store = new Vuex.Store({ state: { todos:[ {id:1, text: '...' ,done: true}, {id:2,text:'...',done: false} ] }, getters: { doneTodos: state => { return state.todos.filter(todo=> todo.done) } } })
Getters는 store.getters 개체로 노출됩니다.
store.getters.doneTodos // [{id:1,text: '...',done:true}]
Getters는 다른 getter를 두 번째 매개변수로 허용할 수도 있습니다.
getters: { doneTodosCount: (state,getters) => { return getters.doneTodos.length } } store.getters.doneTodosCount // -> 1
쉽게
computed: { doneTodosCount() { return this.$store.getters.doneTodosCount } }
mapGetters 도우미 함수를 사용할 수 있습니다.
mapGetters 도우미 함수는 단순히 저장소의 getter입니다. 이는 로컬 계산 속성에 매핑됩니다.
import {mapGetter} form 'vuex' export default { computed: { // 使用对象展开运算符将 getters 混入 ...mapGetters([ ‘doneTodosCount', 'anotherGetter' ]) } }
객체 속성을 사용할 때 getter 속성에 다른 이름을 지정하려는 경우
mapGetters({ // 映射 this.doneCount 为 store.getters.doneTodosCount doneCount: 'doneTodosCount' })
Vuex 스토어에서 상태를 변경하는 유일한 방법은 Vuex에 돌연변이를 제출하는 것입니다
이벤트와 매우 유사합니다. 각 돌연변이에는 문자열 이벤트 유형과 콜백 함수가 있습니다. 이 콜백 함수는 실제로 상태를 변경하는 곳입니다. 그리고 상태를 첫 번째 매개변수로 받아들입니다.
const store = new Vue.Store({ state: { count: 1 }, mutations: { inctement (state) { state.count++ } } })
이 함수는 유형 증분의 돌연변이가 발생했을 때 호출됩니다. "변이 핸들러를 깨우려면 해당 유형으로 store.commit 메소드를 호출해야 합니다. 페이로드(Payload)를 제출합니다. store.commit에 추가 매개변수, 즉 변이 페이로드를 전달할 수 있습니다: "
store.commit('increment')
대부분의 경우 페이로드는 여러 필드를 포함하고 변형을 더 쉽게 기록할 수 있는 객체여야 합니다.
mutations: { increment (state,payload) { state.count += payload.amount } } store.commit('increment', { amount:10 })
对象风格的提交方式
提交mutation 的另一种方式直接使用包含 type 属性的对象:
store.commit({ type: 'increment', amount:10 })
当使用对象风格的提交方式,整个对象作为载荷传给mutation 函数,因此handler保持不变:
mutations: { increment (state, payload) { state.count += payload.amount } }
Mutations 需遵守vue 的响应规则
既然Vuex的store 中的状态是响应式的,那么当我们变更状态时,监视状态的vue更新 ,这也意味值Vue 中的mutation 也需要与使用 Vue 一样遵守一些注意事项。
1. 最好提前在你的store 中初始化好所有的所需要的属性。
2.当需要在对象上提交新属性时,你应该使用
Vue.set(obj, 'newProp', 123)
使用新对象代替老对象 state.obj= {...state.obj ,newProp: 123}
使用常量替代 Mutation 事件类型
使用常量替代 mutation 事件类型在各种 Flux 实现中是很常见的模式
export const SOME_MUTATION = 'SOME_MUTATION'; import Vuex from 'vuex' import {SOME_MUTATION } from './mutation-types' const store = new Vuex.Store({ state: {...} mutations: { // 我们可以使用 ES2015 风格的计算属性命名功能来使用一个常量作为函数名 [SOME_MUTATION] (state) { // mutate state } } })
mutation 必须是同步函数
一条重要的原则是记住 mutation 必须是同步函数。
mutations: { someMutation (state) { api.callAsyncMethod(() => { state.count++ }) } }
在组件中提交 Mutations
你可以在组件中使用 this.$store.commit('xxx') 提交 mutation,或者使使用 mapMutations辅助函数将组建中的methods 映射为 store.commit 调用 (需要在根节点注入 store)
import {mapMutations} from 'vuex' expor default { methods: { mapMutations([ methods: { mapMutations([ 'increment' // 映射 this.increment() 为 this.$store.commit('increment') ]), mapMutations({ add: 'increment' // 映射 this.add() 为 this.$store.commit('increment') }) } ]) } }
Actions
在mutation 中混异步调用会导致你的程序很难调试。
Actions
Action 类似于 mutation,不同在于。
Action 提交的是 mutation ,而不是直接变更状态。
Action 可以包含任意异步操作。
注册一个简单的 action
const store = new Vuex.Store({ state: { count:0 }, mutations: { increment (state) { state.count++ } }, actions: { increment (context){ context.commit('increment') } } })
Action 函数接受一个与store 实例具有相同方法和属性的context 对象,因此你可以调用 context.commit 提交一个mutation,或者通过 context.state 和context.getters 来获取 state 和 getters 当我们在之后介绍到Modules时,你就知道 context 对象为什么不是store 实例本身了。
actions: { increment({commit}){ commit('increment') } }
分发 Action
Action 通过 store.dispatch 方法触发:
store.dispatch('increment')
我们可以在 action 内部执行异步操作。
actions: { incrementAsync({commit}){ setTimeout(() => { commit('increment') },1000) } }
Actions 支持同样的载荷方式和对象方式进行分发
// 以载荷形式分发 store.dispatch('incrementAsync',{ amount:10 }) // 以对象形式分发 store.dispatch({ type: 'incrementAsync', amount:10 })
在组件中分发 Action
你在组件中使用 this.$store.dispatch('xxx')
分发 action,或者使用map Actions辅助函数将组件的methods 映射为store.dispatch 调用
import {mapActions } from 'vuex' export default{ methods:([ 'increment' // 映射 this.increment() 为 this.$store.dispatch('increment') ]) mapActions({ add: 'inctement' // 映射 this.add() 为 this.$store.dispatch('increment') }) }
组合 Actions
Action 通常是异步的,那么如何知道 action 什么时候结束。
你需要明白 store.dispatch 可以处理被处触发的action 的回调函数返回的Promise并且 store.dispatch 仍旧返回Promise
actions: { actionA({commit}){ return new Promise((resolve)=>{ setTimeout (() => { commit('someMutation') resolve() },1000) }) } }
现在你可以
store.dispatch('actionA').then(()=>{ //... })
在另一个 action 中也可以
actions: { actionB({dispath,commit}){ return dispatch('actionA').then(() => { commit('someOtherMutation') }) } }
我们利用async/ await
// 假设 getData() 和 getOther() 返回的是一个 Promis actions:{ async actionA ({commit}){ commit('gotData',await getData()) }, async actionB({dispatch,commit}){ await dispatch('actionA') // 等待 actionA 完成 commit('goOtherData', await getOtherData()) } }
Modules
使用单一状态树,当应用变的很大的时候,store 对象会变的臃肿不堪。
Vuex 允许我们将store 分割到模块。每一个模块都有自己的state, mutation,action, getters, 甚至是嵌套子模块从上到下进行类似的分割。
const moduleA = { state: {...}, mutations: {...} actions: {...} getters:{...} } const moduleA = { state: {...}, mutations: {...} actions: {...} } const store = new Vuex.Store({ modules: { a:moduleA, b:moduleB } }) store.state.a // -> moduleA 的状态 store.state.b // -> moduleB 的状态
模块的局部状态
对于模块内部的 mutation 和 getter, 接收的第一个参数是模块的局部状态。
const moduleA = { state: {count:0}, mutations: { increment (state) { // state 模块的局部状态 state.count++ } }, getters: { doubleCount (state) { return state.count * 2 } } }
同样对于模块内部的action, context.state 是局部状态,根节点的窗台石context.rootState:
const moduleA = { actions: { incrementIfOddOnRootSum ({state, commit ,rootState}) { if((state.count + rootState.count) %2 ===1){ commit('increment') } } } }
对于模块内部的getter,跟节点状态会作为第三个参数:
const moduleA = { getters: { getters: { sumWithRootCount (state,getters,rootState) { return state.count + rootState.count } } } }
命名空间
模块内部的action, mutation , 和 getter 现在仍然注册在全局命名空间 这样保证了多个模块能够响应同一 mutation 或 action. 也可以通过添加前缀 或者 后缀的
方式隔离各个模块,以免冲突。
// 定义 getter, action , 和 mutation 的名称为常量,以模块名 ‘todo' 为前缀。 export const DONE_COUNT = 'todos/DONE_COUNT' export const FETCH_ALL = 'todos/FETCH_ALL' export const TOGGLE_DONE = 'todos/TOGGLE_DONE' import * as types form '../types' // 使用添加了解前缀的名称定义, getter, action 和 mutation const todosModule = { state : {todo: []}, getters: { [type.DONE_COUNT] (state) { } } actions: { [types.FETCH_ALL] (context,payload) { } }, mutations: { [type.TOGGLE_DONE] (state, payload) } }
模块动态注册
在store 创建之后,你可以使用 store.registerModule 方法注册模块。
store.registerModule('myModule',{})
模块的状态将是 store.state.myModule.
模块动态注册功能可以使让其他Vue 插件为了应用的store 附加新模块
以此来分割Vuex 的状态管理。
项目结构
Vuex 并不限制你的代码结构。但是它规定了一些需要遵守的规则:
1.应用层级的状态应该集中到单个store 对象中。
2.提交 mutation 是更改状态的唯一方法,并且这个过程是同步的。
3.异步逻辑应该封装到action 里面。
只要你遵守以上规则,如何组织代码随你便。如果你的 store 文件太大,只需将 action、mutation、和 getters 分割到单独的文件对于大型应用,我们会希望把 Vuex 相关代码分割到模块中。下面是项目结构示例
├── index.html ├── main.js ├── api │ └── ... # 抽取出API请求 ├── components │ ├── App.vue │ └── ... └── store ├── index.js # 我们组装模块并导出 store 的地方 ├── actions.js # 根级别的 action ├── mutations.js # 根级别的 mutation └── modules ├── cart.js # 购物车模块 └── products.js # 产品模块
上面是我整理给大家的,希望今后会对大家有帮助。
相关文章:
위 내용은 vuex의 중국어 문서에 대한 자세한 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!