Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Confusing namespaced api #1500

Open
dcrystalj opened this issue Feb 1, 2019 · 10 comments
Open

Confusing namespaced api #1500

dcrystalj opened this issue Feb 1, 2019 · 10 comments

Comments

@dcrystalj
Copy link

@dcrystalj dcrystalj commented Feb 1, 2019

What problem does this feature solve?

The most confusing thing when using namespaced vuex is inconsistant api with state and getters.

Example:
to access state
this.$store.state.user.name

to access getter
this.$store.getters['user/fullName']

This is so confusing for me and my coworkers. Is there reason to have this inconsistency?

Problem occurs when you try to watch getters
example:

watch: {
  '$store.state.user.name': {
    handler(name) {
      console.log(name)
    },
  },
  '$store.getters[user/fullName]': { // not working
    handler(fullName) {
      console.log(fullName)
    },
  },
}

Current solution Is to use mapGetters() helper for getters only. Why? because of weird api.
Please note that we try to avoid mapGetters, mapState helpers... due to explicitly in large app

What does the proposed API look like?

Add api for getters same as is for state.

Example:
$store.gettters.user.fullName

@LinusBorg

This comment has been minimized.

Copy link
Member

@LinusBorg LinusBorg commented Feb 3, 2019

Getters are computed properties. And just like you can have nested objects in your component's data, but not nested computed props, we can have nested (namespaced) state objects in vuex, but not nested getters.

So we have to do the namespacing like we do it for actions and mutations: with a slash-separated string path: 'namespace/action|mutation|getter'.

Seen that way, the state is actually the one exception to the rule, not the getters.

It it impossible to provide an API like you proposed? no, certainly not. It's just that so far, we so far felt that getters, actions and mutations sharing the same namespace syntax makes sense.

@Akhawais

This comment has been minimized.

Copy link

@Akhawais Akhawais commented Feb 26, 2019

+1 for $store.gettters.user.fullName

I understand the need to differentiate state from actions/mutations/getters however it looks much cleaner to have it in the same style as namespaced state.

Could it be possible to provide an option for this upon creating a store?

@dcrystalj

This comment has been minimized.

Copy link
Author

@dcrystalj dcrystalj commented Feb 26, 2019

an API like you proposed? no, certainly not. It's just that so far, we so far felt that getters, actions and mutations sharing the same namespace syntax makes sense.

The way we are using vuex in our company is that we always use $store.dispatch('namespace/action') in components and we never use mutations. so far this feels ok, except possible errors in naming (less autocompletion)

to render data we use {{ $store.state.user.fullName }} or {{ $store.getters['user/fullName'] }} and we never use mapGetters or mapState. We could write extra getter for every state just to have things consistent, but as you know, less code less bugs + less work.

Another incosistent things in api are parameters for getters, actions and mutations; but this is for another issue.

I believe allowing to have consistant api $store.state['user/fullName'] would be better but i prefer object like style which is less prone to errors and feels less hackish.

@mathieustan

This comment has been minimized.

Copy link

@mathieustan mathieustan commented Mar 20, 2019

You should use mapState or mapGetters, which make it more readable.
Exemple:

import { mapState, mapGetters } from 'vuex';

export default {
  computed: {
    ...mapState({
      userFullName: state => state.user.fullName,
    }),
    // OR
    ...mapGetters({
      userFullName: 'user/getUserFullName',  // (getters name should be different)
    }),
  },
  watch: {
    userFullName() {
      ....
    },
  },
};
@barakbd-bluevine

This comment has been minimized.

Copy link

@barakbd-bluevine barakbd-bluevine commented Apr 5, 2019

I agree, the difference in API is confusing.
https://vuex.vuejs.org/guide/modules.html#binding-helpers-with-namespace

First of all, the docs do not have an example of mapGetters with moduled stores.
When is comes to modules, mapActions (array declaration) is different than mapGetters(object declaration).
APIs should have consistent design for an easier learn curve.

@dcrystalj

This comment has been minimized.

Copy link
Author

@dcrystalj dcrystalj commented Apr 5, 2019

@mathieustan for large scale app we found out that using any mapXxxx is just

  • adding extra work
  • hiding variables in code namespace, makes it hard to see where does it comes from
  • less readable
  • makes it easy to mess consistent naming across app (each developer can make different mapping)
  • more code, more bugs

so we never use this helper and I can tell you how much better life is :D
But I agree that in docs it is all about mapXxxx and you always get a filling that this is the way to go.
I think all this mapXxxx should be removed from docs examples so the newbies would know where does things come from and not be thinking we should use it like this because it is in the docs.

@yolio2003

This comment has been minimized.

Copy link

@yolio2003 yolio2003 commented May 2, 2019

another Confusing example:
i think this:

...mapState([
  'modulex/count'
]),

should be equal to :

...mapState('modulex', {
  'modulex/count': 'count',
}),

and much more easier! but it's not!!!

@yiliang114

This comment has been minimized.

Copy link

@yiliang114 yiliang114 commented Jun 13, 2019

if a module has many properties, there will be lots of redundant codes such as $store.state.user.a, $store.state.user.b, $store.state.user.c, $store.state.user.d,$store.state.user.e ... i do not like to repeat. Maybe you mean i could use object destructuring but i think if you use destructuring to declare as global variables it just

  • adding extra work
  • hiding variables in code namespace, makes it hard to see where does it comes from
  • less readable
    too.
@pikax

This comment has been minimized.

Copy link

@pikax pikax commented Aug 31, 2019

I found that using createnamespacedhelpers is more readable than using mapXXX.

I disagree with @dcrystalj, if each developer uses different naming for things, I think that's an issue to be discuss by the team.

// you can change the component variable name, to better describe where it comes from
...mapGetters('user', {
  userName: 'name'
})

same end result as:

// user.store.js
export userStore = createNamespacedHelpers('user', module);

// component{User}.Vue
import {userStore} from './user.store.js'
...userStore.mapGetters({
  userName: 'name'
})
@dcrystalj

This comment has been minimized.

Copy link
Author

@dcrystalj dcrystalj commented Aug 31, 2019

@pikax your solution is still making code verbose and tedious.

...mapGetters('user', {
  userName: 'name'
})

this is just making one more layer of abstraction dev has to hold in the head. using $store.getters.user.name would be as clear as crystal and also one line of code.
Please note that when having example of one component it's not problem. This is problematic when app is huge/ multiple years of work

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
8 participants
You can’t perform that action at this time.