Skip to content

Instantly share code, notes, and snippets.

@jhkueh
Created February 9, 2018 04:49
Show Gist options
  • Save jhkueh/93be71f388b97eddd3fa23ea9f170fe9 to your computer and use it in GitHub Desktop.
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.
@nagi1
Copy link

nagi1 commented Oct 13, 2021

This isn't helpful at all (respect), because defining the tree structure upfront in the state isn't something real world application do. most of the time you have no idea what the object will have inside of it.

Plus defining nestedObj structure upfront in the state makes it reactive by design and when you don't have that structure in your backyard ready to go, you have to do hacky stuff to get reactivity working.

@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