Vue.js and Immutable.js
Asked Answered
B

2

10

I'm working on a Vue.js application where I have to deal with deeply nested data structures (trees and forests).

After reading about using simple data structures, pure functions and reducing (non-local) mutation, I belief that embracing those ideas would increase the maintainability and simplicity of my code.

While implementing a tree manipulation module using nothing but pure functions, I learned two things:

  • avoiding unintentional mutation of nested objects in JavaScript requires a lot of attention and discipline, especially with larger teams
  • I don't like littering my code with cloneDeep() invocations

Yesterday, I stumbled upon Immutable.js, which looks great to me. After a bit of playing around with it, I feel like it makes my pure functions much easier to reason about.

My Vue.js components would use fromJS(treeNode) and treeNode.toJS() when interacting with the manipulation module.

My question: is it technically possible to Vue.js and Immutable.js together? What are things to keep in mind? Are people using this combination in production? I found this post, which seems to suggest the opposite. That's all I could find.

What are the caveats or practical downsides? Would you suggest to use Immutable.js or to keep deeply cloning regular objects?

edit: updated my question in response to the votes, to make it (less) opinion-based

Blotch answered 27/1, 2018 at 11:18 Comment(0)
P
7

Just reading about this myself, and apparently not: https://forum.vuejs.org/t/immutable-js-with-vue/6366

Personally answered 9/2, 2018 at 14:39 Comment(0)
Y
0

I just tried this (out of curiosity).

<!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>
Ypsilanti answered 29/5, 2020 at 3:33 Comment(1)
It looks like you put in some work, well done. However, please expand beyond just the code. Why did you try this? How did it solve the issue at hand?Medicinal

© 2022 - 2024 — McMap. All rights reserved.