在vue中涉及到比较复杂的数据流转、交互,咱们通常都会考虑用vux来进行数据的状态管理。常常使用,时常想它是怎么实现的,尝试简易实现一下。vue
<template>
<div>
<h1>Election day!</h1>
<button @click="voteForRed">Vote for 🔴</button>
<button @click="voteForBlue">Vote for 🔵</button>
<h2>Results</h2>
<results :red="red" :blue="blue" />
<total-votes :total="red + blue" />
</div>
</template>
<script>
const TotalVotes = {
props: ['total'],
render (h) {
return h('div', `Total votes: ${this.total}`)
}
}
const Results = {
props: ['red', 'blue'],
render (h) {
return h('div', `Red: ${this.red} - Blue: ${this.blue}`)
}
}
export default {
components: { TotalVotes, Results, },
data: () => ({ red: 0, blue: 0 }),
methods: {
voteForRed () { this.red++ },
voteForBlue () { this.blue++ },
}
}
</script>
复制代码
const state = {
red: 0,
blue: 0,
}
const TotalVotes = {
render: h => h('div', `Total votes: ${state.red + state.blue}`)
}
const Results = {
render: h => h('div', `Red: ${state.red} - Blue: ${state.blue}`),
}
// ...and, inside our main component,...
methods: {
voteForRed () { state.red++ },
voteForBlue () { state.blue++ },
},
复制代码
遗憾的是这不能正常工做,这是为何?由于Vue使用数据方法来触发其“响应式反应”。若是不将数据传递给data,Vue将没法跟踪值更改并更新咱们的组件以做为响应,更新视图。修改一下。git
<template>
<div>
<h1>Election day!</h1>
<button @click="voteForRed">Vote for 🔴</button>
<button @click="voteForBlue">Vote for 🔵</button>
<h2>Results</h2>
<results/>
<total-votes/>
</div>
</template>
<script>
const state = {
red: 0,
blue: 0,
}
const TotalVotes = {
data () { return state },
render (h) {
return h('div', `Total votes: ${this.red + this.blue}`)
},
}
const Results = {
data () { return state },
render (h) {
return h('div', `Red: ${this.red} - Blue: ${this.blue}`)
},
}
export default {
components: { TotalVotes, Results },
data () { return state },
methods: {
voteForRed () { this.red++ },
voteForBlue () { this.blue++ },
},
}
</script>
复制代码
注意github
组件TotalVotes、Results的props已经去除bash
每个组件在state中注册了state,Vue可以追踪状态变化,所以当咱们投票给全部组件时,全部组件都会以适当的值进行从新渲染ide
渲染函数中删除了箭头函数函数
上面的实现方式存在缺陷,每一个组件都要注册state,耦合性较高,继续改进ui
建立共享Vue实例以保持响应式(数据变化触发视图更新)this
import Vue from 'vue'
const state = new Vue({
data () {
return { red: 0, blue: 0 }
},
methods: {
voteForRed () { this.red++ },
voteForBlue () { this.blue++ },
},
})
const TotalVotes = {
render: h => h('div', `Total votes: ${state.red + state.blue}`),
}
const Results = {
render: h => h('div', `Red: ${state.red} - Blue: ${state.blue}`),
}
export default {
components: { TotalVotes, Results },
methods: {
voteForRed () { state.voteForRed() },
voteForBlue () { state.voteForBlue() },
},
}
复制代码
至此实现了简单的状态管理,但咱们的解决方案目前没法在项目之间共享。我须要建立一个Vue实例,填充其数据方法,而后注册一些方法来修改状态,继续封装。spa
<!--模板-->
<template>
<div>
<h1>Election day!</h1>
<button @click="voteForRed">Vote for 🔴</button>
<button @click="voteForBlue">Vote for 🔵</button>
<h2>Results</h2>
<results :red="red" :blue="blue" />
<total-votes :total="red + blue" />
</div>
</template>
<!--js-->
<script>
import Vue from 'vue'
const createStore = ({state, mutations}) => {
return new Vue({
data () {
return {state}
},
methods: {
commit (mutationName) {
mutations[mutationName](this.state)
}
}
})
}
const store = createStore({
state: { red: 0, blue: 0 },
mutations: {
voteForRed (state) { state.red++ },
voteForBlue (state) { state.blue++ }
}
})
const TotalVotes = {
render: h => h('div', `Total votes: ${store.state.red + store.state.blue}`)
}
const Results = {
render: h => h('div', `Red: ${store.state.red} - Blue: ${store.state.blue}`)
}
export default {
components: { TotalVotes, Results },
methods: {
voteForRed () { store.commit('voteForRed') },
voteForBlue () { store.commit('voteForBlue') }
}
}
</script>
复制代码