5

tl;dr

How to access other getters from a parameterized getter? Normally, you can use this.myGetter; but a parameterized getter is implemented as an arrow function, wherein this is undefined. What's the preferred way to handle this case in Pinia?


I'd like to create a parameterized getter (multiSum) in my Pinia store, which accesses another getter (sum).

Getters can be accessed via this, but that won't work from within an arrow function which is used to implemented a parameterized getter: multiSum crashes because this is undefined in the context of the nested arrow function.

getters: {
  sum: (state) => state.a + state.b,
  multiSum: (state) => (count) => this.sum * count // crash: this is undefined
}

In Vuex, parameterized getters can access other getters via a parameter instead of this, which also works in arrow functions. But afaik this API does not existing in Pinia.

I can work around this by capturing the store instance:

multiSum(state) {
  const store = this
  return (count) => store.sum * count
}

This works, but is pretty verbose. Is there a better (more framework-compliant) way to do this?

Estus Flask
  • 206,104
  • 70
  • 425
  • 565
dr_barto
  • 5,723
  • 3
  • 26
  • 47

1 Answers1

8

this can be undefined inside arrow function because it's not interchangeable with regular function and gets a context from parent scope.

The usage of this and state is explained in details in the documentation. Either this or state can be used, but this has better Typescript and thus IDE support.

In the first snippet, state is already available in function scope, there is no need to access this:

multiSum: (state) => (count) => state.sum * count

In the second snippet, const store = this isn't needed because a store is already this.

multiSum() {
  return (count) => this.sum * count
}
Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • 1
    Thanks! I was talking about the API you linked: in the docs it says "Access any other getter via this"; but this does not work with parameterized getters (https://pinia.vuejs.org/core-concepts/getters.html#passing-arguments-to-getters) which are implemented as arrow functions. In the second snippet, `this.sum` fails because `this` inside the arrow function is undefined. Vuex provides a solution for this, by passing the `getters` object as optional argument to getters. (Will update my question.) – dr_barto Feb 06 '22 at 17:53
  • It seems that you have problems with the fundamentals of JS here. multiSum from snippet 2 is regular function that has `this` context. Arrow higher order function doesn't have its own `this` and gets the nearest context, which is multiSum's. `const store = this` is redundant in the OP. – Estus Flask Feb 06 '22 at 20:02
  • You are right in that the 2nd example wasn't correct. If should read instead: `const store = this ; return (count) => store.sum * count` -- I can't use `this.sum` inside the arrow function, that's why I have to capture the outer `this` in a variable. But once again: I know why this doesn't work; I'm not asking for help with JS arrow functions, but rather for a solution in Pinia. – dr_barto Feb 07 '22 at 08:23
  • "I can't use this.sum inside the arrow function" - you can, if `this` is correct context. `const store = this; return (count) => store.sum * count` and `return (count) => this.sum * count` are absolutely the same when used inside `multiSum() {` regular (non-arrow) function. – Estus Flask Feb 07 '22 at 09:03
  • They are not the same. In the one case I bind `this` in a variable outside the arrow function's scope, and can access it this way. Directly accessing `this` inside the arrow function does not work though – dr_barto Feb 07 '22 at 09:34
  • "Directly accessing this inside the arrow function does not work though" - can you provide a way to reproduce the problem? This isn't how arrow functions work, that's why I mentioned the problems with JS , the use of old recipe `var self= this` with arrows always indicates that there are some things about them that need to be studied. Check https://stackoverflow.com/questions/28371982/what-does-this-refer-to-in-arrow-functions-in-es6 . The reason why it didn't work in the OP as `multiSum: (state) => (count) => this.sum * count` is because both functions are arrows. – Estus Flask Feb 07 '22 at 09:56
  • Aaah now I finally get what you mean. The reason why the 2nd example works is not because I captured `this` outside the arrow function, but rather because the arrow function is inside a non-arrow function. So I guess this is indeed the solution, plain and simple: just don't write the parameterized getter with 2 arrow functions. Thanks for your time! – dr_barto Feb 08 '22 at 11:03
  • How with this method you can access other getters inside getter? – rendom Jan 29 '23 at 04:54
  • @rendom Use regular function instead of an arrow and access the whole store as `this`, this is noted in the answer. – Estus Flask Jan 29 '23 at 08:41