vuex-dot icon indicating copy to clipboard operation
vuex-dot copied to clipboard

Question: Handle arrays properly

Open haexhub opened this issue 6 years ago • 5 comments

Hi,

what is the best way to expose items of arrays? store/index.js

export const state  = () => {
  foo: [  
    { bar_1: { attr: 'change me' } }  
  , { bar_2: { attr: 'change me 2' } }  
  ]  
}

export const mutations = {
  do_something (state, { key, value }) {
    // how to handle this properly???
  }

page/foo.vue

<template>
  <input v-model = 'bar_1.attr'/>
  <input v-model = 'bar_2.attr'/>
</template>

<script>
export default {
  computed: {
    ...takeState('foo')
    .expose( ??? )
    .commit('do_soemthing')
    .map()
  }
}
</script>

I would like to expose all attr attributes of the items, namespaced by bar_1 and bar_2. Or at least expose bar_1 and bar_2. Could you help me please with this and show (a) possible solution(s)? Would be great. But I don't want to handle this one by one, instead I would like to pass and handle the array at once and get all the getters and setters for each item in the array.

haexhub avatar Jun 17 '18 16:06 haexhub

Hi, in such situation i create component, to which item via props is passed, using v-for. and, after that, you can expose your item using take() (not takeState)

Foo.vue

<template>
  <bar-edit :bar="bar" v-for="bar in foo" />
</template>

<script>
export default {
  computed: {
    ...mapState(['foo']);
  }
}
</script>

BarEdit.vue

<template>
  <input v-model = 'attr'/>
</template>

<script>
export default {
  props: ['bar']
  computed: {
    ...take('bar')
    .expose( [ 'attr' ] )
    .commit('do_something')
    .map()
  }
}
</script>

yarsky-tgz avatar Jun 17 '18 17:06 yarsky-tgz

Thank you for your quick response! Looks like a reasonable approach. Thank you for that and please keep going with this good work :+1: I'll use it know in my projects :smile:

haexhub avatar Jun 17 '18 18:06 haexhub

Just one more question. It seems to be vue specific. I want to pass all attributes as props, but it seems that in computed propertys this is not available?!. Can you tell me what I'm missing?

components/form-item.vue

export default {
  props: {
    item: {
      type: Object
    , required: true
    }
  , attribute: {
      type: Array
    , default: () => ['value']
    }
  , commit: {
      type: String
    }
  }
/*
, computed: {
    ...take(this.item)
    .expose(this.attribute)
    .commit(this.commit)
    .map()
  } // not working
*/
, computed: {
    ...take('item')
    .expose(['value'])
    .commit('do_soemthing')
    .map()
  } // is working
}

components/form.vue

<template>
  <formItem
    commit = 'do_something'
    :item = 'item'
    attribute = 'value'
  />
</template>

<script>
import formItem from './form-item'
export default {
  data () {
    return {
      item: this.$store.state.form[0]
    }
, components: {
    formItem
  }
}
</script>

I'm a bit confused, could you help me please to see the picture? :smiley: Why can't I just pass the props to your function?

haexhub avatar Jun 17 '18 19:06 haexhub

Solved some parts. Who is able to read, has a clear advantage. (german saying) ^^ In the docu about vuex is written:

// in full builds helpers are exposed as Vuex.mapState
import { mapState } from 'vuex'

export default {
  // ...
  computed: mapState({
    // arrow functions can make the code very succinct!
    count: state => state.count,

    // passing the string value 'count' is same as `state => state.count`
    countAlias: 'count',

    // to access local state with `this`, a normal function must be used
    countPlusLocalState (state) {
      return state.count + this.localCount
    }
  })
}

https://vuex.vuejs.org/guide/state.html#the-mapstate-helper

If you want to use this you need to use a function...

I did this an it worked:


haexhub avatar Jun 17 '18 21:06 haexhub

Who is able to read, has a great advantage (german saying) :smiley: In vuex docs is written:

// in full builds helpers are exposed as Vuex.mapState
import { mapState } from 'vuex'

export default {
  // ...
  computed: mapState({
    // arrow functions can make the code very succinct!
    count: state => state.count,

    // passing the string value 'count' is same as `state => state.count`
    countAlias: 'count',

    // to access local state with `this`, a normal function must be used
    countPlusLocalState (state) {
      return state.count + this.localCount
    }
  })
}

You need to use a function to access this https://vuex.vuejs.org/guide/state.html#the-mapstate-helper

I did this and it worked: components/formItem

export default {
  computed: {
    ...take(state => { return this.item }) // this is the trick
    .expose(['value']) // unfortunately not working here .expose(state => { return this.attribute }) 
    .commit('do_something', arguments) // nore does it here but nice feature?!
    .map()
  }
}

If I pass a secend arguement to so commit function, I get the target as parameter in the mutation and so you are able to mutate the state over this parameter. This is quite usefull, if you don't know where the exact subtree of the state belongs to. For example my store looks like this:

export const state = () => {
  foo: {
    bar: {
      form: [ ] // some Objects
    }
  }
, foo_2: {
    bar_2: {
     form: [ ] // more Objects
    }
  }
}

export const mutations = {
  do_something (state, payload) {
    console.log('vuex payload ', payload)
    payload.target.item.value = payload.value
  }
}

If I pass via props this.$store.state.foo.bar.form I don't know in the component, where the form belongs to. It could be foo.bar or foo_2.bar_2. But with the target parameter, I can mutate the right values. I'm not sure if this is supposed to do so. Doesn't feel well. :confused:

image

Here you can see the target attribute. In target.item is my state I want to handle. I can change the value in the mutation without complains from vuex, that I should not mutate state directly. But it feels strange.

haexhub avatar Jun 17 '18 22:06 haexhub