vuex 表單之痛

最近一個小項目使用 vuejs 技術棧 - vue + vuex + vue-router + element-ui。在作表單的時候遇到一個小問題。javascript

這個表單用於更新用戶信息,原信息來自於 vuex,注入到 computed 中html

computed: mapState({
  user: state => state.users[id]
})

vuex 使用嚴格模式,這意味着不能直接修改 user, 不然會報錯。 我選擇深度克隆一個 user 對象。直接使用解構對象 { ...user } 沒法兼容屬性值爲對象的對象,因此棄用。vue

import _ from 'lodash'

computed: mapState({
  user: state => { return _.cloneDeep(state.users[id]) }
})

保存驗證。select 選擇另外一個選項,組件中 user 會被修改, vuex 中的 user 不會被修改,可是組件視圖沒法被更新。和同事討論了一會,有了下面的猜想:若是視圖能夠被更新,即 component user <=> component 產生雙項綁定。同時,按照 computed 的定義,vuex user 一旦被修改,也會反映到 compoent user,即 vuex user => component user。咱們使用了深度克隆,因此這裏的方向是單向的。java

問題來了,咱們但願 vuex user 只在 form 加載完成後注入到 component 中,以後全部修改僅僅在 component 起做用,直到 component 銷燬。可是上面的模型, vuex 依然和組件狀態綁定,經過 computed,全部在 vuex 上的數據更新都會反映到 component 上,然而 component 還有局部狀態,因此衝突了。而後發生了沒法描述的結果。git

在想清楚這些之前,我找了不少 vuex 表單的最佳實踐,包括官方說明。他們的建議是,應該在每一個表單項目上綁定 input 處理函數,單獨提交 mutation。github

<input :value="message" @input="updateMessage">
// ...
computed: {
  ...mapState({
    message: state => state.obj.message
  })
},
methods: {
  updateMessage (e) {
    this.$store.commit('updateMessage', e.target.value)
  }
}

若是表單項不少,基本沒法維護。何況單獨提交表單項,不符合常理。通常都是全部項目填寫完成,用戶手動提交。vue-router

還有些人,贊同使用非嚴格模式。 那我以爲還不如直接棄用 vuex。我一直以爲 vuex 一邊提供 mutation 用於更新 state,一邊又默承認以採用非嚴格模式,倒不如只提供嚴格模式來的乾淨。
vue + vuex 表單處理vuex

其實咱們之因此以爲這麼難,是由於一開始就想錯了。對於表單,只是加載一次數據,其實用不着 computed,只在 created 或者 mounted 中初始化一次數據就能夠了。element-ui

created () {
  this.user = getUser(id)
}

getUser 可使用 getter, 同時深度克隆。。函數

簡不簡單,驚不驚喜。

喜歡請關注 駑馬和他的專欄。 本篇未提供 demo,稍後會補上,太晚了。

DEMO

最近想作一個 vuejs 開發系列的最佳實踐,建了一個 vue-best-practice, 歡迎指正錯誤和貢獻代碼。另附本篇相關 代碼地址

相關文章
相關標籤/搜索