我正在开发一个 Vue.js 应用程序,我必须处理深度嵌套的数据结构(树和森林)。
在阅读了有关使用简单数据结构、纯函数和减少(非本地)突变的内容后,我相信接受这些想法将提高代码的可维护性和简单性。
在仅使用纯函数实现树操作模块时,我学到了两件事:
cloneDeep()
调用乱扔我的代码昨天,我偶然发现了 Immutable.js,它对我来说看起来很棒。经过一番尝试后,我觉得它让我的纯函数更容易推理。
fromJS(treeNode)
和 treeNode.toJS()
。
我的问题:技术上可以将 Vue.js 和 Immutable.js 结合在一起吗?有哪些注意事项?人们在生产中使用这种组合吗?我发现了这篇post,它似乎暗示了相反的情况。这就是我能找到的全部了。
有哪些注意事项或实际缺点?您会建议使用 Immutable.js 还是继续深度克隆常规对象?
编辑:根据投票更新了我的问题,使其(更少)基于意见
我自己读过这篇文章,显然不是:https://forum.vuejs.org/t/immutable-js-with-vue/6366
我刚刚尝试过这个(出于好奇)。
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/vuex"></script>
<script src="https://unpkg.com/immutable"></script>
</head>
<body>
<div id="app">
<button @click="increment">
+ (Increment)
</button>
{{ count }}
<button @click="decrement">
- (Decrement)
</button>
<hr>
<input v-model="count" placeholder="Change Value"/>
</div>
<script>
const { Store } = Vuex;
const { Map } = Immutable;
const immutableCount = Map({
value: 0
})
const countReducer = ({ state, type, value}) => {
const count = state.count;
let newCount;
switch(type) {
case 'INCREMENT':
newCount = count.update('value', x => x + 1);
break;
case 'DECREMENT':
newCount = count.update('value', x => x - 1);
break;
case 'SET_VALUE':
newCount = count.set('value', value);
break;
}
state.count = newCount;
}
const state = {
count: immutableCount
}
const mutations = {
INCREMENT(state) {
countReducer({
state,
type: 'INCREMENT'
})
},
DECREMENT(state) {
countReducer({
state,
type: 'DECREMENT'
})
},
SET_VALUE(state, value) {
countReducer({
state,
type: 'SET_VALUE',
value
})
}
}
const actions = {
increment({ commit }) {
commit('INCREMENT');
},
decrement({ commit }) {
commit('DECREMENT');
},
setValue({ commit }, value) {
commit('SET_VALUE', value);
}
}
const store = new Store({
state,
mutations,
actions
})
const dispatchers = {
increment() {
this.$store.dispatch('increment');
},
decrement() {
this.$store.dispatch('decrement');
},
setValue(value) {
this.$store.dispatch('setValue', value)
}
}
const count = {
get() {
return this.$store.state.count.get('value');
},
set(value) {
this.setValue(value ? value : 0)
}
}
const computed = {
count
}
const app = new Vue({
el: '#app',
computed,
methods: {
...dispatchers
},
store
})
</script>
</body>
</html>
是的,可以将 Immutable.js 与 Vue.js v3 一起使用。
但这没有任何意义)Immutable.js 破坏了 Vue.js 中的反应系统。在我的示例中,我使用 List 函数创建“myList”并将其用“ref()”包装,并在“description”ref 中链接到该对象。用新人员更新“myList”后,“描述”保持不变。 Vue.js 依赖于可变对象,即代理和突变机制。因此,为了使其与 Immutable.js 一起工作,我需要更新对对象的所有(!)引用,这不是很方便。在这种情况下,每次更新列表“myList”时,我都需要更新“description”对象
<script setup>
import { ref } from "vue"
//import { RouterView } from 'vue-router'
import { List, Map } from "immutable"
const myList = ref(List([
{ id: 1, name: "Quincy" },
{ id: 2, name: "Nathan" },
{ id: 3, name: "Frank" },
{ id: 4, name: "Olivia" },
{ id: 5, name: "Jack" },
{ id: 6, name: "Charlie" },
{ id: 7, name: "Bob" },
{ id: 8, name: "Kathy" },
{ id: 9, name: "Hannah" },
{ id: 10, name: "Alice" },
{ id: 11, name: "Rachel" },
{ id: 12, name: "Mona" },
{ id: 13, name: "Ivy" },
{ id: 14, name: "Peter" },
{ id: 15, name: "Grace" },
{ id: 16, name: "Tina" },
{ id: 17, name: "Eve" },
{ id: 18, name: "Leo" },
{ id: 19, name: "David" },
{ id: 20, name: "Steve" }
]))
//
// const myList = ref([
// { id: 1, name: "Quincy" },
// { id: 2, name: "Nathan" },
// { id: 3, name: "Frank" },
// { id: 4, name: "Olivia" },
// { id: 5, name: "Jack" },
// { id: 6, name: "Charlie" },
// { id: 7, name: "Bob" },
// { id: 8, name: "Kathy" },
// { id: 9, name: "Hannah" },
// { id: 10, name: "Alice" },
// { id: 11, name: "Rachel" },
// { id: 12, name: "Mona" },
// { id: 13, name: "Ivy" },
// { id: 14, name: "Peter" },
// { id: 15, name: "Grace" },
// { id: 16, name: "Tina" },
// { id: 17, name: "Eve" },
// { id: 18, name: "Leo" },
// { id: 19, name: "David" },
// { id: 20, name: "Steve" }
// ])
const description = ref(Map({
name: "John",
age: 22,
city: "Berlin",
country: "Germany",
job: "Software Engineer",
hobbies: ["Programming", "Reading", "Gaming"],
friends: myMap.value,
}))
const addNewPerson = () => {
myList.value = myList.value.push({
id: myList.value.size + 1,
name: "New Person" + (myList.value.size + 1)
})
}
const extendDescription = () => {
description.value = description.value.set("newKey", "newValue")
}
const extendHobbies = () => {
description.value = description.value.set("hobbies", [...description.value.get("hobbies"), "newHobby"])
}
</script>
<template>
<header> my app </header>
<main>
<ul>
<li v-for="item in myList" :key="item.id">
{{ item.name }}
</li>
</ul>
<div>
<button type="button" @click="() => addNewPerson()">
add new person
</button>
</div>
<section>
<h2>description</h2>
<ul>
<li v-for="([k, v], key) in description" :key="key">
<template v-if="k === 'hobbies'">
<ul>
<li>
Hobbies:
</li>
<li v-for="hobby in v" :key="hobby">
{{ hobby }}
</li>
</ul>
</template>
<template v-else-if="k === 'friends'">
<ul>
<li>
Friends::
</li>
<li v-for="item in v" :key="item.id">
{{ item.name }}
</li>
</ul>
</template>
<template v-else>
{{ k }}: {{ v }}
</template>
</li>
</ul>
<div>
<button @click="() => extendDescription()" type="button">
extend description
</button>
</div>
<div>
<button @click="() => extendHobbies()" type="button">
extent hobbies
</button>
</div>
</section>
</main>
</template>
<style scoped>
</style>