vue狀態管理演進

vue狀態管理演進

概述

在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>
複製代碼

image

  • 隔離狀態 讓咱們建立一個state對象,並從那裏管理咱們的整轉態。
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>  
複製代碼
相關文章
相關標籤/搜索