简体   繁体   English

Vue 中的 Immer 数据未更新

[英]Immer data not updating in Vue

I'm trying to use Immer with Vue.我正在尝试将 Immer 与 Vue 一起使用。 It appears that the state is updating, but Vue isn't updating the UI似乎状态正在更新,但 Vue 没有更新 UI

// immutable.js
import produce, { applyPatches } from "immer"

let undo_buffer = []
export var state = { items: [] }
const handle_add_patch = (patch, inverse_patches) => {
  console.log("Inverse Patches: ", inverse_patches)
  undo_buffer.push(inverse_patches)
}
export const add_item = (item_name) => {
  console.log("Starting add_item call")
  const next_state = produce(
    state,
    draft => {
      draft.items.push({ name: item_name })
    },
    handle_add_patch
  )
  console.log("next state: ", next_state)
  state = next_state
}
export const undo = () => {
  const undo_patch = undo_buffer.pop()
  if (!undo_patch) return
  let new_state = applyPatches(state, undo_patch)
  console.log("New State: ", new_state)
  state = new_state
}
<!-- item_list.Vue -->
<template>
  <div>
    <button @click.prevent="add_item()">Add Item</button>
      {{ items }}
    <button @click.prevent="undo()">Undo</button>
  </div>
</template>
<script>
import * as immutable from './immutable.js'
export default {
  computed: {
    items: function(){ return immutable.state.items }
  },
  methods: {
    add_item(){
      console.log("State Before: ", immutable.state)
      immutable.add_item("Hello")
      console.log("State After: ", immutable.state)
    },
    undo(){
      console.log("State Before: ", immutable.state)
      immutable.undo()
      console.log("State After: ", immutable.state)
    }
  }
}
</script>

The console.log shows that the items array is changing, but the items in the Vue template just shows an empty array. console.log 显示 items 数组正在发生变化,但 Vue 模板中的 items 只是显示一个空数组。 How can I make this visible within Vue?我怎样才能使它在 Vue 中可见?

Computed properties are cached and they aren't recomputed until associated component data is changed.计算的属性会被缓存,并且在关联的组件数据更改之前不会重新计算它们。 Since Immer object isn't a part of the component, recomputation never occurs.由于 Immer 对象不是组件的一部分,因此永远不会发生重新计算。

Caching can be prevented by using getter method instead of computed property:可以通过使用 getter 方法而不是计算属性来防止缓存:

{{ getItems() }}

...

methods: {
  getItems: () => immutable.state.items
  addItem() {
    immutable.add_item("Hello");
    this.$forceUpdate();
  }
}

A more direct approach is to force a property to be recomputed:更直接的方法是强制重新计算属性:

data() {
  return { _itemsDirtyFlag: 0 }
},
computed: {
  items: {
    get() {
      this._itemsDirtyFlag; // associate it with this computed property
      return immutable.state.items;
    }
},
methods: {
  updateItems() {
    this._itemsDirtyFlag++;
  },
  addItem() {
    immutable.add_item("Hello");
    this.updateItems();
  }
}

A similar approach that uses Vue.util.defineReactive internal is used by vue-recomputed . vue-recomputed使用了类似的使用Vue.util.defineReactive internal 的方法。

This issue is not related with Immer.此问题与 Immer 无关。 vuejs caches the computed properties hence they do not update when your data updates. vuejs 缓存计算的属性,因此当您的数据更新时它们不会更新。 This is mentioned clearly in vuejs docs at https://v2.vuejs.org/v2/guide/computed.html#Computed-Caching-vs-Methods这在https://v2.vuejs.org/v2/guide/computed.html#Computed-Caching-vs-Methods的 vuejs 文档中明确提到

Instead of a computed property, we can define the same function as a method.我们可以将相同的函数定义为方法,而不是计算属性。 For the end result, the two approaches are indeed exactly the same.对于最终结果,这两种方法确实完全相同。 However, the difference is that computed properties are cached based on their reactive dependencies.但是,不同之处在于,计算属性是根据它们的反应依赖来缓存的。 A computed property will only re-evaluate when some of its reactive dependencies have changed.计算属性仅在其某些反应性依赖项发生更改时才会重新评估。

Since Immer is not a reactive dependency, the computed property never runs again.由于 Immer 不是响应式依赖项,因此计算属性永远不会再次运行。

Solution for this would be to change the computed property to a method.解决方案是将计算属性更改为方法。 This way it will not be cached and the method will run each time with updated value.这样它就不会被缓存,并且该方法每次都会以更新的值运行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM