How to make dispatches synchronous - reactjs

I have an the following function that is executed on button click:-
const modelClick = async(modelcategory, modelname)=>{
const curr_model = allModels.filter(model => model.model === modelname && model.version === version)
console.log("curr_model= ", curr_model[0]);
await dispatch(setModel(curr_model[0]))
await dispatch(getModelsOfType(curr_model[0]['model category']))
console.log("models=", models);
let temp;
temp = models.filter(model => model.modelname === curr_model[0]['model_type'])
console.log("temp inside modelClick= ", temp);
}
dispatch(getModelsOfType(curr_model[0]['model category'])) : This function queries the dynamodb and update the global redux state 'models'. I then want to filter the models based on type.
THE ISSUE i am facing is that the code below the dispatch gets executed before the state gets updated. It gives an error saying models is undefined. I want to run it synchronously so that the filter line gets executed only after models is updated. How can that be achieved ?
Here is the action creater function:-
export const getModelsOfType=(modeltype)=> async(dispatch) => {
dispatch({
type: GET_MODELS_OF_TYPE_REQUEST
})
let params = {
model_type: modeltype
}
axios
.post(`${BACKEND_URL}get-models`, params, {
headers: {
"Content-Type": "application/json",
},
})
.then((res)=>{
console.log("DYNAMO DB RESULT= ", res.data.Items)
dispatch({
type: GET_MODELS_OF_TYPE_SUCCESS,
payload: res.data.Items
})
})
.catch((err) => {
console.log("err >>", err);
dispatch({
type: GET_MODELS_OF_TYPE_FAIL
})
});
}

Instead of dispatching the action in the component. what you can do is dispatch the second action inside the first actions then block.
export const setModel=(your arguments)=> async(dispatch) => {
dispatch({
type: ACTION_REQUEST
})
axios
.post(// make API call)
.then((res)=>{
dispatch({
type: ACTION_SUCCESS,
payload: res
})
// now dispatch the second action here .
dispatch(getModelsOfType(your arguments))
})
.catch((err) => {
console.log("err >>", err);
dispatch({
type: ACTION_FAILURE
})
});
}

Related

how to make a dispatch wait for the first dispatch to run

i have 2 dispatch inside the useEffect, is there a way i can make the bottom dispatch to wait for the first one to run. i need to get the post._id from the first to pass to the second. please doesn't anyone have an idea on how to solve this?
useEffect(() => {
dispatch(getPost(params.slug));
dispatch(listComment(post._id));
}, [dispatch]);
// getPost action
export const getPost = (slug) => async(dispatch) => {
try {
dispatch({
type: types.POST_REQUEST
});
const {
data
} = await axios.get(`http://localhost:8080/api/posts/${slug}`);
dispatch({
type: types.POST_SUCCESS,
payload: data,
});
} catch (err) {
dispatch({
type: types.POST_FAIL,
payload: err.response && err.response.data.message ?
err.response.data.message :
err.message,
});
}
};
You can introduce a loading state for Post, and use that in another useEffect to achieve that
useEffect(() => {
dispatch(getPost(params.slug));
}, [dispatch]);
useEffect(() => {
if(!post.loading) {
dispatch(listComment(post._id));
}
}, [dispatch, post.loading]);
It's possible to coordinate this by observing loading flags with useEffect, but a simpler solution in my opinion is to extend the thunk to dispatch another action after the response for the post is available:
// actions:
export const listComments = (postId) => async (dispatch) => {
/* thunk that fetches comments on a post */
}
// Fetch post for slug, optionally with comments.
export const getPost = (slug, withComments = false) => async(dispatch) => {
dispatch({ type: types.POST_REQUEST });
try {
const { data } = await axios.get(`http://localhost:8080/api/posts/${slug}`);
dispatch({ type: types.POST_SUCCESS, payload: data });
if (withComments) {
dispatch(listComments(data.id));
}
} catch (err) {
const payload = err.response && err.response.data.message ?
err.response.data.message : err.message;
dispatch({ type: types.POST_FAIL, payload });
}
};
// In the component:
dispatch(getPost(slug, true));
you can try with below snippet, also will this post.id get after first dipatch or it will be present?
useEffect(() => {
dispatch(getPost(params.slug));
}, [required dispaencies]);
useEffect(() => {
if(!post._id || some loading){
dispatch(listComment(post._id));
}
},[required depencies])

Axios get in stock items

I am trying to filter products whether it is available or not.
Not sure how to pass an axios request with ">" logic.
I've started to create an Action
export const listProductAvailable = () => async (dispatch) => {
dispatch({
type: PRODUCT_AVAILABLE_LIST_REQUEST,
});
try {
const { data } = await Axios.get(`/api/products?countInStock>0`);
dispatch({ type: PRODUCT_AVAILABLE_LIST_SUCCESS, payload: data });
} catch (error) {
dispatch({ type: PRODUCT_AVAILABLE_LIST_FAIL, payload: error.message });
}
};
But I don't think that such a request is possible.
const { data } = await Axios.get(/api/products?countInStock>0);
Also, I don't see myself changing my Product Model creating an isAvailable boolean field as it would be redundant with countInStock =0 or not.

The function call inside the redux action doesnot get executed

I'm trying my first react application with redux, along with Thunk as middle ware. When calling the action from one of the components, the action is hit but the code inside the action return is not executed. I have no clue what I'm missing here. I'm also using Firestore to get the data.
export const getBikeTypes = () => {
console.log('outside return')
return (dispatch, getState, { getFireBase, getFireStore }) => {
console.log('inside return')
const firestore = getFireStore();
firestore.collection('BikeTypes').get()
.then((response) => {
console.log(response)
return response
}).then(() => {
dispatch({ type: 'GET_BIKETYPES' });
}).catch((err) => {
dispatch({ type: 'GET_BIKETYPES_FAIL', err });
})
}
};
I think you should dispatch action with the payload once you get the response.
const firestore = getFireStore();
firestore.collection('BikeTypes').get()
.then((response) => {
dispatch({ type: 'GET_BIKETYPES', payload: response })
})

Call multiple dispatch after getting axios response Redux

I need to call multiple dispatches after getting the response from axios how can I do, it the current way I'm doing is only allowing me to send one dispatch and when trying to fire the second dispatch it gives and error saying that the res is not found.
export const getItem = (id) => dispatch =>{
dispatch(setLoading);
axios.get(`http://localhost:8081/getItem?id=${id}`)
.then(
res => dispatch({
type: GET_ITEM,
payload: res.data
})
)
}
I need to fire a secondary dispatch after getting the response, the functionality of the secondary dispatch, I need to this after getting the return from axios is because a unique email and id is stored in the response, so I need to get the id, from the response to fire the secondary call.
export const getUserItem = (payload) => dispatch =>{
dispatch(setItemsLoading);
axios.get(`http://localhost:8081/getUserItems?email=${payload.email}&id=${payload.id}`)
.then(
res => dispatch({
type: GET_USER_ITEM,
payload: res.data
})
)
}
Is there a way to dispatch 2 after a response is received from axios?
With arrow syntax you need to add brackets if you want to do more than a single statement:
export const getItem = (id) => dispatch =>{
dispatch(setLoading);
axios.get(`http://localhost:8081/getItem?id=${id}`)
.then(
res => {
dispatch({
type: GET_ITEM,
payload: res.data
})
//second dispatch
dispatch({
type: GET_ITEM,
payload: res.data
})
}
)
}

Axios-Redux in React to an Express endpoint-both .then and .catch triggered

I'm using a Redux Form to send a POST call to an Express endpoint. The endpoint is supposed to return the successfully saved object, or an error.
The endpoint successfully saves the posted data and returns the JSON. But Axios in the Redux action picks up both the .then and the .catch triggers-in the following action, it logs the following:
successful response: { …}
failure response: undefined
What am I doing wrong?
My Axios action:
export function addPlot(props) {
const user = JSON.parse(localStorage.getItem('user'));
return function(dispatch) {
axios
.post(
`${ROOT_URL}/plots`,
{
props
},
{ headers: { authorization: user.token } }
)
.then(response => {
console.log('successful response: ', response.data);
const plotModal = document.getElementById('plotModal');
plotModal.modal('dispose');
dispatch({ type: PLOT_ADDED, payload: response.data });
dispatch({ type: ADDING_PLOT, payload: false });
dispatch({
type: NEW_PLOT_GEOJSON,
payload: ''
});
})
.catch(response => {
console.log('failure response: ', response.data);
dispatch(authError(PLOT_ADD_FAILURE, 'Failed to add plot'));
});
}
My endpoint:
exports.newPlot = async (req, res, next) => {
console.log(JSON.stringify(req.body.props));
let company;
if (req.user.companyCode !== 'Trellis') {
company = req.user.companyCode;
} else {
company = req.body.props.company;
}
const {
name,
feature,
growerPhone,
plotCode,
rootStock,
region,
variety,
grower,
planted
} = req.body.props;
const plot = new Plot({
name,
grower,
variety,
planted,
region,
rootStock,
plotCode,
growerPhone,
feature,
company
});
try {
const newPlot = await plot.save();
res.json(newPlot);
} catch (e) {
console.log("couldn't save new plot", JSON.stringify(e));
return res.status(422).send({ error: { message: e, resend: true } });
}
};
You could use redux-thunk middleware to manage async actions.
The problem I see is that you are not dispatching the axios action, you must call dispatch(this.props.addPlot(props))in order to do something in the redux store.

Resources