How to call Pinia action from another action?
Asked Answered
A

4

9

Is there a way to call Pinia store action from another action in the same store? For example, I have Pinia store like this:

export const useCounter = defineStore({
    id: 'counter',

    state: () => ({
        counter: 0
    }),

    actions: {
        addOne() {
            this.state.counter++
        },
        addTwo() {
            // Can i call here addOne action?
            // Things like this not working:
            this.addOne();
            this.addOne();
            // This is not working too:
            this.actions.addOne();
            this.actions.addOne();
        }
    }
});

Can I call AddOne action inside addTwo?

Ancestral answered 9/6, 2022 at 14:38 Comment(1)
"not working" is not accurate enough description of the problemIntenerate
S
10

You can indeed access methods of the same store by this. Just used it in my own store's action method. The getPost action method is accessing multiple methods of the same store through this (checkPost, fetchPost) and it works just fine.

import {defineStore} from 'pinia';
import axios from 'axios';
const axiosInstance = axios.create({
    baseURL: window.wue.restUrl,
})

export const useBlogStore = defineStore(
    'blog',
    {
        state: () => ({
            posts: [],

        }),
        getters: {
            postCount(state) {
                return state.posts.length;
            },
            checkPost(state) {
                return (property, value) => (state.posts.find(post => post[property] === value));
            }
        },
        actions:{
            addPost(post) {
                this.posts.push(post)
            },
            async getPost(property, value) {
                if (this.checkPost(property, value)) {
                    return this.checkPost(property, value);
                } else {
                    return this.fetchPost(property, value);
                }
            },
            async fetchPost(property, value) {
                try {
                    let json;
                    if (property === "slug") {
                        json = await axiosInstance.get(`posts?slug=${value}`);
                    } else if (property === "id") {
                        json = await axiosInstance.get(`posts/${value}`);
                    }
                    const post = json.data[0];
                    this.addPost(post);
                    return post;
                } catch (error) {
                    alert(error);
                    console.log(error);
                }
            },
     }
});
Strasbourg answered 17/10, 2022 at 18:41 Comment(0)
A
4

After some researching, I've found some sort of answer. Don't believe it's ok to do things like this, but this works.

Basically, we just need to call the main store function (in my case, this is useCounter) just inside action we need to call another action from same storage, and then call actions of storage as usually.

export const useCounter = defineStore({
    id: 'counter',

    state: () => ({
        counter: 0
    }),

    actions: {
        addOne() {
            this.state.counter++
        },
        addTwo() {
            const counterStorage = useCounter();
            counterStorage.addOne();
            counterStorage.addOne();
        }
    }
});

There is an example of this on Pinia documentation, but it's saying we can do this to call action from ANOTHER storage, so that confused me.

Ancestral answered 9/6, 2022 at 18:19 Comment(3)
I am facing the same issue.. and it seems a bit weird that one has to call the create an instance of the store again.. can you share the link of the example you mentioned in your answer that's in the Pinia documentation?Brigitte
@AlimBolar I didn't find it in Pinia documentation, but I saw there that you can access another store in this one like this. I just try it as experiment and it worked. pinia.vuejs.org/cookbook/composing-stores.html#nested-storesAncestral
Pinia sucks ~~~~~🍍Shanahan
Y
1

Scenario 1 - Using Vue3 + Pinia (optionsAPI) + Fetch (instead of AXIOS).

a. Within the same store, I am able to call another action (eg action_b) from an action (eg action_a) by using "this.action_b". (This is the response mentioned by FullStack Alex as above).

b. However, when I try to call action_b as part of a FETCH response in action_a, this does not work. In this situation the response provided by Назар Семенюк worked. i.e., within action_a I had to call the store again as a variable (eg store_x) and then use it as a prefix to call action_b (store_x.action_b).

FETCH code used is as per the format provided in https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch

export const useixStore = defineStore('ix', {
state: () => ({...}),
actions: {
  action_b () {...},
  action_a () {
    ...
    const ix = useixStore(); // INTRODUCED TO MAKE THIS WORK
    ...
      async function postData(url = "", data = {}) {
    // Default options are marked with *
    const response = await fetch(url, {
      method: "POST", // *GET, POST, PUT, DELETE, etc.
      mode: "cors", // no-cors, *cors, same-origin
      cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
      credentials: "same-origin", // include, *same-origin, omit
      headers: {
        "Content-Type": "application/json",
        // "Content-Type": "application/json;charset=UTF-8",
      },
      redirect: "follow", // manual, *follow, error
      referrerPolicy: "no-referrer", // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
      body: JSON.stringify(data), // body data type must match "Content-Type" header
    });
    return response.json(); // parses JSON response into native JavaScript objects
  }
  postData(url, i_json)
  .then(function(res) {
    ... 
    this.action_b   // THIS DOES NOT WORK
    ix.action_b     // THIS WORKED AFTER INTRODUCING ix WITHIN THIS action_a
    ...
  });
....

Scenario 2 - Using Vue3 + Pinia (setup) + Fetch (instead of AXIOS).

In this scenario using Pinia (using setup instead of OptionsAPI), everything is normal.

a. Within the same store, I am able to call another action (eg action_b) from an action (eg action_a) by using "action_b". (This is similar to the response mentioned by FullStack Alex as above). b. Even within a FETCH response, this works as expected and simple "action_b" works.

Yoheaveho answered 13/5, 2023 at 8:5 Comment(3)
Can you please provide your FETCH code? Looks like you have another context in fetch.Ancestral
Have added the codes to my first post.Yoheaveho
In your case, this is might not work because you are using function(), that creates its own execution context. Replacing function() in .then with arrow function () => {} should fix your problem.Ancestral
A
1

The top response (FullStack Alex) doesn't work in Typescript. I finally found this GH issue: https://github.com/vuejs/pinia/discussions/1299

Essentially it seems that your getters need to by typed. Once I did that, I was able to use my getter in an action.

Ascetic answered 18/5, 2023 at 3:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.