Различные способы реализации двусторонней привязки данных для одного и того же компонента в Vuex

#vue.js #vuejs2 #vue-component #vuex #vuex-modules

#vue.js #vuejs2 #vue-компонент #vuex #vuex-модули

Вопрос:

У меня есть адресный компонент, который имеет базовую форму адреса с такими данными, как имя, улица, город, штат, страна. Я использую его для источника и назначения.

Образец шаблона

 <div class="row">
    <div class="col-6" id="src">
        <Address :address="src" />
    </div>
    <div class="col-6" id="dest">
        <Address :address="dest" />
    </div>
</div>
  

Адресный компонент
Я использую действие Vuex (с модулем) для получения данных из API (который может возвращать или не возвращать какие-либо адресные данные) и изменения состояния моего хранилища.

Пример состояния:

 Address:{
    src:{
       name:'',
       street:'',
       city:'',
       state:'',
       country:'',   
    },
    dest:{
       name:'',
       street:'',
       city:'',
       state:'',
       country:'',   
    }
}
  

Я хочу добиться двусторонней привязки данных между моими компонентами состояния и адреса посредством мутации.

Компонент адреса для src должен изменять Address.src.(название, улица, город, штат, страна) в состоянии, а компонент адреса для dest должен изменять Address.dest.(название, улица, город, штат, страна) в состоянии

Я попытался использовать props и emit, vuex-map-fields, следуя этому сообщению, и это не сработало.

Я не знаю, как правильно это реализовать.

Я публикую этот вопрос как новичок, чтобы получить помощь в том, как правильно это сделать?

Ответ №1:

Если я правильно понял вашу проблему, я следую приведенному ниже шаблону:

 Make API Call --> data is updated in Vuex --> picked up by computed prop in component
  

В принципе, в моем компоненте я могу создать вычисляемый prop, который извлекает данные из хранилища Vuex, примерно так:

 computed:{
  sourceAddress(){
    return this.$store.state.Address.src;
  },
  destinationAddress(){
    return this.$store.state.Address.dest;
  }
}

  

Затем я могу связать эти вычисленные реквизиты с моим адресным компонентом следующим образом:

 <div class="row">
    <div class="col-6" id="src">
        <Address :address="sourceAddress" />
    </div>
    <div class="col-6" id="dest">
        <Address :address="destinationAddress" />
    </div>
</div>

  

Теперь всякий раз, когда объект Address будет обновляться в Vuex (через вызов API), эти вычисляемые реквизиты будут выбирать изменение и обновлять компонент Address соответственно.

 // sample pseudo code

mutations:{

  updateAddress(state, {type,payload}){
    if(type==="destination"){ 
       // update destination address
      }
    else { 
       //update source address
     }
    
  }

},

actions:{

  makeApiCall(context){
    // lets say call succeeds and you have some data to update for destination address
   context.commit('updateAddress',{type:"destination", payload:"data-you-want-to-update});
  }

}

  

Комментарии:

1. Это решает проблему передачи данных из vuex в адресный компонент, как я могу обновить изменение адресного компонента в состояние vuex? Я хочу добиться двусторонней привязки данных @nishkaush

2. Сначала определите a mutation , который при получении данных обновит состояние. Затем вызовите эту мутацию из вашего Vuex Action (после успешного вызова API и фактически содержит некоторые данные для обновления).

3. @AkashPreet, если вы довольны решением, не могли бы вы отметить его как ответ для будущих читателей. Спасибо

Ответ №2:

Вы можете использовать vuex getters для получения данных вашего хранилища. Vue обрабатывает более элегантный способ извлечения данных ( two way binding ) в компоненты с помощью функций помощников vuex. Вы можете прочитать больше о вспомогательных функциях vuex здесь

 // store.js
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const store = {
   Address: {
    src: {
       name:'',
       street:'',
       city:'',
       state:'',
       country:'',   
    },
    dest: {
       name:'',
       street:'',
       city:'',
       state:'',
       country:'',   
    }
  }
}

const getters = {
   src: state => state.Address.src,
   desc: state => state.Address.desc
}

const mutations = {
  setSrc(state, srcObj) { // You can play around this to optimize if you can
    state.Address.src = srcObj
  },
  setDesc(state, descObj) {
    state.Address.desc = descObj
  }
}
const actions = {
   makeApiCall({ commit }, { type, params }) {
     yourApiCall(params).then((res) => {
       if (type === 'src') {  // You can play around this to optimize if you can
          commit('setSrc', res)
       } else {
          commit('setDesc', res)
       }
     })
   }
}

export default new Vuex.Store({ state, getters, mutations, actions})
  
 //main.js
// all other imports

import store from './store'

new Vue({
  el: '#app',
  store
})

  
 In your component

<Address :address="src"/>
<Address :address="desc"/>

import { mapGetters, mapActions } from 'vuex'

computed: {
  ...mapGetters(['src', 'desc']) // these are updated automatically when store changes and available on this.src/this.desc 
},
methods: {
  ...mapActions(['makeApiCall']) // you can directly call using this // this.makeApiCall({ type: 'src', params: {} }) 
}
  

Комментарии:

1. Спасибо за ответ @Naren, но это все равно не решит проблему. Я хочу изменить состояние, если мы изменим значение в полях ввода компонента адреса. Например: если API возвращает Address.src.name как Naren (который будет сохранен в состоянии), тогда страница загрузится с Naren в поле ввода имени адреса. Если я изменю Naren на Akash, то он должен измениться в состоянии (Address.src.name сейчас должен быть Акаш).

2. вы не должны изменять состояние напрямую, вы должны делать только с мутациями. Согласно документам Vuex: The only way to actually change state in a Vuex store is by committing a mutation , прочитайте это для получения дополнительной информации

3. Если вы хотите изменить состояние из поля ввода, добавьте мутацию в хранилище и обновите состояние с помощью этой мутации. const mutations = { changeName(state, name) { state.Address.name = name }}