Skip to content

Instantly share code, notes, and snippets.

@jhkueh
Created February 9, 2018 04:49
Show Gist options
  • Select an option

  • Save jhkueh/93be71f388b97eddd3fa23ea9f170fe9 to your computer and use it in GitHub Desktop.

Select an option

Save jhkueh/93be71f388b97eddd3fa23ea9f170fe9 to your computer and use it in GitHub Desktop.
vuex deep nested objects

Vuex and Deep Nested Objects


Vue.js provides a good example for working with deep nested objects or tree data structures. But, how about when Vuex is involved?

Fortunately, Evan You (Vue.js' creator) gives us a hint:

...Or, you can use the same flat structure and use ids to reference nested items, and use a Vuex getter in each tree item component to retrieve its children.

So, how do we go about doing that? After a few attempts getting nested objects' reactivity to work, here is what I did.

Let's say we have our nested objects that looks like this in Vuex:

const store = new Vuex.Store({
    state: {
        nestedObj: [
            { id: 1, parent_id: null, content: 'Hello' },
            { id: 2, parent_id: 1,    content: 'World' },
            { id: 3, parent_id: 2,    content: 'Welcome!' },
            { id: 4, parent_id: null, content: 'Cool.' },
            { id: 5, parent_id: 2,    content: 'Back!' },
        ]
    },
    ...
})

Then, in our getters:

    getters: {
        getChildrenByID: ({ nestedObj }) => (id) => {
            return nestedObj.filter( obj => obj.parent_id == id );
        },
        getParent({ nestedObj }) {
            return nestedObj.filter( obj => obj.parent_id == null );
        }
    },
    ...
})

Next, in our Child.vue component:

<template>
    <div class="box">
        <p>
            {{ data.body }}
        </p>

        <!-- Child -->
        <child v-for="(item, index) in getChildrenByID(data.id)"
               :key="item.id"
               :data="item">
        </child>
    </div>
</template>

<script>
import { mapGetters } from "vuex";

export default {
    props: ['data'],
    computed: {
        ...mapGetters([
            'getChildrenByID',
        ]),
    },
}
</script>

Finally, in our Parent.vue component:

<template>
    <div class="section">
        <child v-for="(child, index) in getParent"
               :key="child.id"
               :data="child">
        </child>
    </div>
</template>

<script>
import { mapGetters } from "vuex";

export default {
    computed: {
        ...mapGetters([
            'getParent',
        ]),
    },
}

So now, when we do nestedObj.push({ id: 6, parent_id: 5, content: 'New content!!' }) in our Vuex's mutation, the nested object view will be updated accordingly (reactive).

Additional Resources

  • Normalizr — normalizes nested JSON according to a schema.
  • Tips for working with nested data.
@jhkueh
Copy link
Author

jhkueh commented Oct 14, 2021

@nagi1 sorry to hear that the note didn't help your case. However, do bear in mind that this was written in Feb 2018 (3+ years ago, almost 4), and in a different context when Vue.js' major release is version 2. There might be a better state management library out there or a better way of doing things. Unfortunately, I haven't dabble myself in Vue.js for a few years now, so I can't really help you but to advice that you explore, read and ask around.

@DimitrijeD
Copy link

DimitrijeD commented May 1, 2022

@jhkueh This is exactly what I needed :) tnx

Only thing is, in my case i need
nestedObj update -> { id: 5, parent_id: 2, content: 'Back! UPDATED' },

to accualy trigger mapped getter in child component, but it doesn't, or im doing something wrong :/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment