Method in vuex action return undefined - javascript

I have the following method in my Vuex action:
const actions = {
async fetchByQuery({ commit, title }) {
console.log(title);
//other codes
},
};
And method to reach to vuex action:
methods: {
...mapActions(["fetchByQuery"]),
getData(title) {
console.log("teacher");
this.fetchByQuery(title);
}
}
But the console.log() from action is giving undefined output in the console.
What am I missing here ??

You got the parameters inside your action wrong.
({ commit, title }) has to be ({ commit }, title)
Otherwise you would have to call it with an object with a property title.

Vuex actions expect two parameters, the context object { commit } and the payload (title, in your case)
Change your action declaration to this:
const actions = {
async fetchByQuery({ commit }, title) {
console.log(title);
//other codes
},
};

Related

No reactivity between service and component

I take out the logic in the service separately from the component.
There is a property in the logic, on which the display of the element in the component depends
The property is declared like this:
function serviceAbonent () {
...
const switchAdd = ref(false)
...
return { switchAdd }
}
In the component, I get this property like this:
const { stitchAdd }= serviceAbonent()
In this method, I call the service method, which changes the value of the property
function newItemAdd () {
serviceAbonent().add(newItemBlack, 'Black', 'CreateDate')
}
service method:
async function add (newItem :any, list: string, defaultSort: string) {
switchAdd.value = false ...
The problem is that when the value changes, the value only changes in the service, but does not change in the component. Why is that ?

How to set state to api data in the store

I am trying to set my state to the data I'm getting from my API with a GETTER in the store.
during the mounted() lifecyclehook trigger the GETTER getProducts() which looks like this:
export const getters = {
async getProducts() {
axios.get('/api/products')
.then(res => {
var data = res.data
commit('setProducts', data)
})
.catch(err => console.log(err));
}
}
In the GETTER I try to trigger a MUTATION called setProducts() which looks like this:
export const mutations = {
setProducts(state, data) {
state.products = data
}
}
But when I run this I get the error ReferenceError: commit is not defined in my console.
So obviously what goes wrong is triggering the MUTATION but after looking for 2 days straight on the internet I still couldn't find anything.
I also tried replacing commit('setProducts', data) with:
this.setProducts(data)
setProducts(data)
Which all ended with the error "TypeError: Cannot read properties of undefined (reading 'setProducts')"
If your function getProduct is defined in a Vue component, you have to access the store like this :
this.$store.commit('setProducts', data)
If your function is not defined in a Vue component but in an external javascript file, you must first import your store
import store from './fileWhereIsYourStore.js'
store.commit('setProducts', data)
If your getters export is literally the definition of your store's getters, you can use the solution of importing the store first, but you should know that it is clearly not a good practice to make commits in getters. There must be a better solution to your problem.
EDIT : To answer your comment, here's how you could do it:
// Your store module
export default {
state: {
products: []
},
mutations: {
SET_PRODUCTS(state, data) {
state.products = data
}
},
actions: {
async fetchProducts(store) {
await axios.get('/api/products')
.then(res => {
var data = res.data
store.commit('SET_PRODUCTS', data)
})
.catch(err => console.log(err));
}
}
}
Now, you can fetch products and populate your store in each of your components like this :
// A random Vue Component
<template>
</template>
<script>
export default {
async mounted() {
await this.$store.dispatch('fetchProducts')
// now you can access your products like this
console.log(this.$store.state.products)
}
}
</script>
I didn't tested this code but it should be ok.
Only actions do have commit in their context as you can see here.
Getters don't have commit.
Otherwise, you could also use mapActions (aka import { mapActions } from 'vuex'), rather than this.$store.dispatch (just a matter of style, no real difference at the end).
Refactoring your code to have an action as Julien suggested is a good solution because this is how you should be using Vuex.
Getters are usually used to have some state having a specific structure, like sorted alphabetically or alike. For common state access, use the regular state or the mapState helper.

Reactjs - Why can't i set state?

Hi i'm trying to fetch a user data from jsonplaceholder and update my state with that data. I had no problem fetching the data and logging it to the console. But when i try to setState, i still get an empty object.
I appreciate any help. Thanks.
This is my code:
class ProfilePage extends React.Component {
state = {
profileDetails: {},
};
componentDidMount() {
this.fetchDetails();
}
fetchDetails = async () => {
const baseUrl = "https://jsonplaceholder.typicode.com";
const pathname = this.props.history.location.pathname;
const response = await fetch(`${baseUrl}${pathname}`);
const data = await response.json();
console.log(data); // I can see the data i want here in the console.
this.setState = { profileDetails: data };
console.log(this.state.profileDetails); // I get an empty object here.
};
render() {
return <h1>Name: {this.state.profileDetails.name}</h1>;
}
}
export default ProfilePage;
Thanks everyone for taking the time to answer. Apparently i used setState wrong and missed the fact that it's asynchronous.
From docs of setState
React does not guarantee that the state changes are applied
immediately.
If you want to use up-to-date data, use callback argument (and use it as function, instead of assignment, because it is a method, not a property)
this.setState({ profileDetails: data }, () => {
console.log(this.state.profileDetails)
})
Change this
this.setState = { profileDetails: data };
console.log(this.state.profileDetails);
into this
this.setState({ profileDetails: data });
Put console.log(this.state.profileDetails); inside render for you to see your new state.
setState is a function that recieves data as parameters.
but you use it like setState is a json object
setState - is a method.
Please change code like this - this.setState({ profileDetails: data });
The right way to set state is this,
this.setState({ profileDetails: data })
You have to set state by this way only.
Give a condition for check the data is available or not:-
if(data)
this.setState = ({ profileDetails: data });

React - getDerivedStateFromProps and axios

I would like to set state variable books as result of API. I cannot do it in componentDidMount, because I don't have token at the beginning and need it to get result from API. Nothing happens with state books when I run following code. If I put state.books=res.data before return I got a result, but after manually refresh page.
constructor(props) {
super(props);
this.state = {
books: [],
};
}
and
static getDerivedStateFromProps(nextProps, state) {
if (nextProps.token){
axios.defaults.headers = {
"Content-Type": "application/json",
Authorization: "Token " + nextProps.token
}
axios.get('http://127.0.0.1:8000/api/book/own/')
.then(res => {
return {
books: res.data,
}
})
}
data from the API looks like:
{
id: 66,
isbn: "9780545010221",
title: "Title",
author: "Author,Author",
}
In the render method I call component with this.static.books data.
Could you please advise me?
This is a very common pitfall: you are returning something inside the promise handler (then), thinking that that would return from the function that created the promise (getDerivedStateFromProps). That's not the case.
I'm afraid you can't use getDerivedStateFromProps for asynchronous code like this. However, you don't have to, given that react is, uhm, reactive.
componentDidUpdate() {
if (this.props.token) {
axios.get('http://127.0.0.1:8000/api/book/own/')
.then(res => this.setState({books: res.data})) ;
}
}

How to pass an argument to functions mapped using ...mapActions(...)?

Considering the following passage
export default {
methods: {
...mapActions(["updateData", "resetData"]);
}
}
I'd like to pass in a parameter into the called functions. Not certain how to do so properly while still retaining the ...mapAction() call, I had to rewrite to the following.
export default {
methods: {
// ...mapActions(["updateData", "resetData"])
updateData: function() { this.$store.dispatch("updateData", "names") },
resetData: function() { this.$store.dispatch("resetData"); }
}
}
Is this the only way?
You can just pass the parameter to the method, where you are calling it. you can only send one parameter, which will be available in the actions. You don't have to do anything special when using mapActions
For example you can call it like:
<button #click=updateData({data1: 1, data2: 2})>
and in the vuex store:
const actions = {
updateData: (state, data) => {
//You will get passed parameter as data here
},
and you can still use mapActions:
export default {
methods: {
...mapActions(["updateData", "resetData"]);
}
}
see working fiddle here: you can see passed parameter in the alert :)
Here is the implementation of mapActions from vuex repo
export function mapActions (actions) {
const res = {}
normalizeMap(actions).forEach(({ key, val }) => {
res[key] = function mappedAction (...args) {
return this.$store.dispatch.apply(this.$store, [val].concat(args))
}
})
return res
}
You can see it takes the args passed and puts them as a second argument of dispatch function.

Categories