Vue.js 和 Immutable.js

问题描述 投票:0回答:3

我正在开发一个 Vue.js 应用程序,我必须处理深度嵌套的数据结构(树和森林)。

在阅读了有关使用简单数据结构、纯函数和减少(非本地)突变的内容后,我相信接受这些想法将提高代码的可维护性和简单性。

在仅使用纯函数实现树操作模块时,我学到了两件事:

  • 避免 JavaScript 中嵌套对象的无意突变需要大量的关注和纪律,尤其是对于较大的团队
  • 我不喜欢用
    cloneDeep()
    调用乱扔我的代码

昨天,我偶然发现了 Immutable.js,它对我来说看起来很棒。经过一番尝试后,我觉得它让我的纯函数更容易推理。

我的 Vue.js 组件在与操作模块交互时将使用

fromJS(treeNode)
treeNode.toJS()

我的问题:技术上可以将 Vue.js 和 Immutable.js 结合在一起吗?有哪些注意事项?人们在生产中使用这种组合吗?我发现了这篇post,它似乎暗示了相反的情况。这就是我能找到的全部了。

有哪些注意事项或实际缺点?您会建议使用 Immutable.js 还是继续深度克隆常规对象?

编辑:根据投票更新了我的问题,使其(更少)基于意见

javascript data-structures vue.js tree immutable.js
3个回答
7
投票

我自己读过这篇文章,显然不是:https://forum.vuejs.org/t/immutable-js-with-vue/6366


0
投票

我刚刚尝试过这个(出于好奇)。

<!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>

0
投票

是的,可以将 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>


© www.soinside.com 2019 - 2024. All rights reserved.