Immer 数据未在 Vue 中更新
Immer data not updating in Vue
我正在尝试将 Immer 与 Vue 结合使用。看起来状态正在更新,但 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>
console.log显示items数组正在变化,但是Vue模板中的items只是显示一个空数组。我怎样才能使它在 Vue 中可见?
计算的属性被缓存,并且在关联的组件数据更改之前不会重新计算它们。由于 Immer 对象不是组件的一部分,因此永远不会发生重新计算。
缓存可以通过使用 getter 方法而不是计算 属性:
来防止
{{ getItems() }}
...
methods: {
getItems: () => immutable.state.items
addItem() {
immutable.add_item("Hello");
this.$forceUpdate();
}
}
更直接的方法是强制重新计算属性:
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();
}
}
vue-recomputed
使用了一种使用 Vue.util.defineReactive
内部的类似方法。
此问题与 Immer 无关。 vuejs 缓存计算属性,因此它们不会在您的数据更新时更新。 https://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.
由于 Immer 不是反应性依赖项,因此计算的 属性 再也不会 运行s。
解决方案是将计算的 属性 更改为方法。这样它就不会被缓存,并且该方法每次都会 运行 更新值。
我正在尝试将 Immer 与 Vue 结合使用。看起来状态正在更新,但 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>
console.log显示items数组正在变化,但是Vue模板中的items只是显示一个空数组。我怎样才能使它在 Vue 中可见?
计算的属性被缓存,并且在关联的组件数据更改之前不会重新计算它们。由于 Immer 对象不是组件的一部分,因此永远不会发生重新计算。
缓存可以通过使用 getter 方法而不是计算 属性:
来防止{{ getItems() }}
...
methods: {
getItems: () => immutable.state.items
addItem() {
immutable.add_item("Hello");
this.$forceUpdate();
}
}
更直接的方法是强制重新计算属性:
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();
}
}
vue-recomputed
使用了一种使用 Vue.util.defineReactive
内部的类似方法。
此问题与 Immer 无关。 vuejs 缓存计算属性,因此它们不会在您的数据更新时更新。 https://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.
由于 Immer 不是反应性依赖项,因此计算的 属性 再也不会 运行s。
解决方案是将计算的 属性 更改为方法。这样它就不会被缓存,并且该方法每次都会 运行 更新值。