如何监听来自 vuex 的计算数组的变化

Posted

技术标签:

【中文标题】如何监听来自 vuex 的计算数组的变化【英文标题】:How to listen changes of array in computed which comes from vuex 【发布时间】:2020-02-01 08:16:46 【问题描述】:

我有一个由商店状态组装而成的计算数组:

computed: 
  ...mapGetters([
    '$tg',
  ]),
  ...mapState(
    podcastList: state => state.listening.podcastList,
  ),
  tabList: 
    get() 
      const questionTitle = this.$tg('questions');
      const list = this.podcastList.map((poadcast, index) => (
        ...poadcast,
        title: `$questionTitle$index + 1`,
        answers: [...poadcast.answers],
      ));
      return list;
    ,
    set(value) 
      // I want dispatch action here..
      console.log('set', value);
    ,
  ,

podcastList的构造是一个对象数组:

[ 
   
    id: 1,  
    answers: [ 
       id: 1, content:'foo',  id: 2, content: 'bar'
    ]
  , //.....
]

我正在使用v-for 来制作一组input,它与answers 绑定。 它看起来像:

<div class="columns is-vcentered" v-for="(answer, index) in tab.answers" :key="index">
 <input type="text" v-model="answer.content"/>
</div>
// tab is an element of my tabList

我的问题:如果我更改了 input 的值,则不会触发计算的 setter。我会收到消息的

“错误:[vuex] 不在突变处理程序之外改变 vuex 存储状态。”

我知道我不能直接修改状态,但是我不知道如何分发动作,例如official website。有人可以帮忙吗?非常感谢。

【问题讨论】:

致电set 时要更改什么?您能否显示触发该错误的代码,它将帮助我们更好地了解您尝试执行的操作 我想更新“podcastList”的状态。当我更改输入值时弹出错误(在 vuex.esm.js 中) 我想保持 v-model 的灵活性,也要遵循 vuex 的模式。 【参考方案1】:

v-model 仅在您将 tabList 映射到其中时才有效(类似于组件中的 v-model="tabList"

您必须直接更改每个答案,使用value@input 而不是v-model

<div class="columns is-vcentered" v-for="(answer, index) in tab.answers" :key="index">
 <input type="text" :value="answer.content"
       @input="$store.commit('updateAnswer',  podcastId: tab.id, answerId: answer.id, newContent: $event.target.value )" />
</div>
// tab is an element of my tabList

updateAnswer 突变如:

mutations: 
  updateAnswer (state,  podcastId, answerId, newContent ) 
    state.listening.podcastList
        .find(podcast => podcast.id === podcastId)
        .map(podcast => podcast.answers)
        .find(answer => answer.id === answerId).content = newContent;
  

--

您也许可以通过创建方法来减少样板:

methods: 
  updateAnswer(tab, answer, event) 
    this.$store.commit('updateAnswer',  podcastId: tab.id, answerId: answer.id, newContent: event.target.value );
  

并像这样使用它:

<input type="text" :value="answer.content" @input="updateAnswer(tab, answer, $event)" />

或者通过创建一个组件(可能是功能性的):

Vue.component('answer', 
  template: `
    <input type="text" :value="answer.content"
           @input="$store.commit('updateAnswer',  podcastId: tab.id, answerId: answer.id, newContent: $event.target.value )" />
  `
  props: ['tab', 'answer']
)

并像这样使用它:

<div class="columns is-vcentered" v-for="(answer, index) in tab.answers" :key="index">
 <answer :tab="tab" :answer="answer"/>
</div>

【讨论】:

这是通过输入事件更新状态的唯一方法吗?因为我有很多输入来绑定这些事件.. :( 无论如何,谢谢你的帮助~ 我添加了一些替代品,看看你是否认为有更好的选择。恐怕你真的不能使用computedset功能。这只有在你有v-model="tabList" 时才有效。从技术上讲,您可以将watcher 添加到您的计算属性中并像您的设置器一样使用它,但这会很复杂,因为您必须(1)克隆每个答案(在answers: [...poadcast.answers] 中),更重要的是,(2 ) 您必须在每次触发观察者时准确找出编辑了哪个答案。

以上是关于如何监听来自 vuex 的计算数组的变化的主要内容,如果未能解决你的问题,请参考以下文章

从一个html跳到另一个htmlvue可以监听路由变化吗

vue 监听对象属性的变化

vue 是如何深度监听data的变化的

从一个html跳到另一个html vue可以监听路由变化吗

在vue中使用resize事件监听浏览器窗口的变化

如何监听JS数组的变化