Can't return response from redux-thunk - reactjs

I'm calling an action from a component:
this.props.createWebsite(this.state)
This calls an action and passes in some state. The action looks like this:
export const createWebsite = data => {
return (dispatch, getState) => {
return axios.post(
API.path + 'website/',
{
// some data
}
)
.then(response => {
})
.catch(error => {
})
}
}
I want to handle the response and error in the component that called this, rather than in the action itself. How can I do this? I have tried:
this.props.createWebsite(this.state).then(response => { /**/ }).catch(error => { /**/ })
This sort of works but it doesn't catch errors.

You need to remove the catch from the createWebsite declaration.
It handle the error and to not propagate it. So the error is lost.
To get it :
remove the catch
export const createWebsite = data => {
return (dispatch, getState) => {
return axios.post(
API.path + 'website/',
{
// some data
}
)
.then(response => {
return response;
})
}
}
rethrow the exception
export const createWebsite = data => {
return (dispatch, getState) => {
return axios.post(
API.path + 'website/',
{
// some data
}
)
.then(response => {
return response;
})
.catch(error => {
// Do something
throw error;
})
}
}

Related

How to make a PATCH request in ReactJS ? (with Nestjs)

nestjs controller.ts
#Patch(':id')
async updateProduct(
#Param('id') addrId: string,
#Body('billingAddr') addrBilling: boolean,
#Body('shippingAddr') addrShipping: boolean,
) {
await this.addrService.updateProduct(addrId, addrBilling, addrShipping);
return null;
}
nestjs service.ts
async updateProduct(
addressId: string,
addrBilling: boolean,
addrShipping: boolean,
) {
const updatedProduct = await this.findAddress(addressId);
if (addrBilling) {
updatedProduct.billingAddr = addrBilling;
}
if (addrShipping) {
updatedProduct.shippingAddr = addrShipping;
}
updatedProduct.save();
}
there is no problem here. I can patch in localhost:8000/address/addressid in postman and change billingAddr to true or false.the backend is working properly.
how can i call react with axios?
page.js
const ChangeBillingAddress = async (param,param2) => {
try {
await authService.setBilling(param,param2).then(
() => {
window.location.reload();
},
(error) => {
console.log(error);
}
);
}
catch (err) {
console.log(err);
}
}
return....
<Button size='sm' variant={data.billingAddr === true ? ("outline-secondary") : ("info")} onClick={() => ChangeBillingAddress (data._id,data.billingAddr)}>
auth.service.js
const setBilling = async (param,param2) => {
let adressid = `${param}`;
const url = `http://localhost:8001/address/`+ adressid ;
return axios.patch(url,param, param2).then((response) => {
if (response.data.token) {
localStorage.setItem("user", JSON.stringify(response.data));
}
return response.data;
})
}
I have to make sure the parameters are the billlingddress field and change it to true.
I can't make any changes when react button click
Since patch method is working fine in postman, and server is also working fine, here's a tip for frontend debugging
Hard code url id and replace param with hard coded values too:
const setBilling = async (param,param2) => {
// let adressid = `${param}`;
const url = `http://localhost:8001/address/123`; // hard code a addressid
return axios.patch(url,param, param2).then((response) => { // hard code params too
console.log(response); // see console result
if (response.data.token) {
// localStorage.setItem("user", JSON.stringify(response.data));
}
// return response.data;
})
}
now it worked correctly
#Patch('/:id')
async updateProduct(
#Param('id') addrId: string,
#Body('billingAddr') addrBilling: boolean,
) {
await this.addrService.updateProduct(addrId, addrBilling);
return null;
}
const ChangeBillingAddress = async (param) => {
try {
await authService.setBilling(param,true).then(
() => {
window.location.reload();
},
(error) => {
console.log(error);
}
);
}
catch (err) {
console.log(err);
}
}
const setBilling= async (param,param2) => {
let id = `${param}`;
const url = `http://localhost:8001/address/`+ id;
return axios.patch(url,{billingAddr: param2}).then((response) => {
if (response.data.token) {
localStorage.setItem("user", JSON.stringify(response.data));
}
return response.data;
})
}

how to get all data from a request

I receive data from the server and try to get "name" from the "one" object and get an undefined error. If you remove the replacement in request, the line "fetchData (response.data)" with "fetchData (response.data.one)" and in the selector "return state.one.name;" to "return state.name;" the result returns data. What is causing this error? Query and reference to the same objects.
request
export function fetchData (data) {
return {
type: "GET_DATA_REQUEST",
payload: data
}
}
export function fetchDataRequest(url) {
return(dispatch)=> {
fetch(url)
.then(response => {
if (!response.ok) {
throw new Error(response.statusText);
}
return response;
}
)
.then(response => response.json())
.then(response => dispatch(fetchData(response.data)))
}
}
selector
export const getRequestCity = (state) => {
return state.one.name;
}
You can check if the object one is present before accessing it like below -
export const getRequestCity = (state) => {
if (state.one) {
return state.one.name;
}
}

Getting value of Dispatch in React/Redux

I am trying to implement an account verification via the twilio api where it texts a user a code and it should set the state of generatedCode to that value, but i am having a difficult time getting that value of the dispatch. If i do a simple await with axios call it works fine, but not so much with a dispatch
action:
export const attemptRegisterVerify = (phone) => async (dispatch) => {
dispatch(registerVerifyBegin());
await postRegisterVerifyPhone(phone)
.then((res) => {
dispatch(registerVerifySuccess(res.data));
})
.catch((error) => {
dispatch(registerVerifyFail(error));
});
};
handleVerification:
const handleVerification = async (values) => {
const { email, phone } = values;
setModal(true);
try {
const response = await axios.post(
'http://localhost:8000/api/v1/auth/register/check-duplicate',
{
email,
phone,
}
);
if (response.data.success) {
switch (response.data.message) {
case 0:
try {
const response = await dispatch(
attemptRegisterVerify({ to: phone })
);
console.log(response);
// if (response.data.success) {
// setGeneratedCode(response.data.message);
// console.log(generatedCode);
// } else {
// console.log(response.data.message);
// }
} catch (error) {
console.log(error);
}
break;
case 1:
console.log('Email Address already in use.');
break;
case 2:
console.log('Phone number already in use.');
break;
case 3:
console.log('Email and Phone in use.');
break;
}
} else {
console.log(response.data.message);
}
} catch (error) {
console.log(error);
}
};
The console.log(response) returns undefined. Is there a way for it to wait until that dispatch is completed, then proceed?
export const attemptRegisterVerify = (phone) => async (dispatch) => {
dispatch(registerVerifyBegin());
await postRegisterVerifyPhone(phone)
.then((res) => {
dispatch(registerVerifySuccess(res.data));
return res.data; // return console.log(res.data) works
})
.catch((error) => {
dispatch(registerVerifyFail(error));
});
};
Dispatch returns what you return in the function call. In the case of an async thunk, it'll return Promise<void> by default unless you return something.
If in your attemptRegisterVerify thunk, if you add return 'test' to the end of it, then your console.log(response) would log 'test'.
In a non-thunk, the return value of the dispatch would be the action that was generated.

Async Actions resolve before fetch result is retrieved

I'm using Redux with redux-thunk to retrieve categories from an API. I have an action called viewCategory that depends on having categories in the store state.
I used the example of fetching Reddit posts from the Redux site:
https://redux.js.org/advanced/asyncactions#actions-js-asynchronous
The problem I have is that when I call viewCategory the promise thinks it's resolved when REQUEST_CATEGORIES is dispatched and not RECEIVE_CATEGORIES. So if log my state in the then statement I have an
empty list of categories.
export function viewCategory(urlKey) {
return (dispatch, getState) => {
dispatch(fetchCategoriesIfNeeded()).then(() => {
let state = getState();
console.log(state); // should have categories
let categories = [...state.categories.mainCategories,
...state.categories.specialCategories];
let matchCategory = categories.find((category) => {
return category.custom_attributes.find(x => x.attribute_code === "url_key").value === urlKey;
});
dispatch({
type: Categories.VIEW_CATEGORY,
category: matchCategory
});
});
};
}
The functions that decide if categories should be fetched at all:
function shouldFetchCategories(state) {
const categories = state.categories;
if(categories.isFetching || categories.mainCategories.length > 0) {
return false;
} else {
return true;
}
}
export function fetchCategoriesIfNeeded() {
return (dispatch, getState) => {
if(shouldFetchCategories(getState())) {
return dispatch(fetchCategories());
} else {
return Promise.resolve();
}
};
}
The function that contains the actual fetch call:
function fetchCategories() {
return (dispatch, getState) => {
dispatch(requestCategories());
const {locale} = getState().settings;
return fetch(`${BASE_URL}/categories/list`, {
method: "POST",
headers: {
"Accept-Language": locale
},
body: "Not interesting for stackoverflow"
})
.then(response => response.json())
.then(json => {
if(json !== undefined && json.items){
dispatch(receiveCategories(json.items));
}
});
};
}
The functions where I dispatch types REQUEST_CATEGORIES & RECEIVE_CATEGORIES:
function requestCategories() {
return {
type: Categories.REQUEST_CATEGORIES
};
}
function receiveCategories(result) {
const mainCategories = result.filter(category => category.level === 2);
const subCategories = result.filter(category => category.level === 3);
const categories = mainCategories.map(category => {
let children = subCategories.filter(x => x.parent_id === category.id);
return {
...category,
children
};
});
let specialCategories = categories.splice(categories.length - 2, 2);
return {
type: Categories.RECEIVE_CATEGORIES,
categories: categories,
specialCategories: specialCategories,
receivedAt: Date.now()
};
}
Any idea what I am doing wrong here? If you need any extra code or information please let me know.

How can I return a promise from my ActionCreator in React Redux

I have the following handler that dispatches two actions...
_onPress = () => {
let { request,userId} = this.props;
this.props.dispatch(acceptRequest(request.id,userId))
this.props.dispatch(navigatePop());
}
What I would like this to look like instead is the following...
_onPress = () => {
let { request,userId} = this.props;
this.props.dispatch(acceptRequest(request.id,userId))
.then(this.props.dispatch(navigatePop()))
}
My ActionCreator looks like this...
export function acceptRequest(requestId,fulfilledBy){
return dispatch => {
fulfillments.create(requestId,fulfilledBy)
.then(response => response.json())
.then(fulfillment => {
dispatch(_acceptRequestSuccess(fulfillment))
})
.catch(err => {
console.log(err);
dispatch(_acceptRequestError(error))
})
}
}
I am aware that they have many middleware(s) that people suggest, but I don't
see how any of them fit this scenario unless I am completed doing somthing
incorrectly.
In my particular case, I only want to dispatch the seond action if the first is
successful, but I don't want to do this from the action creator because then
it is less reusable.
Ok, so I misunderstood you, you should mention that you are using redux-thunk.
I don't think redux action should return a promise, I think you should do everything in the component and then play with the promise, like this:
_onPress = () => {
let { request,userId} = this.props;
fulfillments.create(requestId,fulfilledBy)
.then(response => response.json())
.then(fulfillment => {
this.props.dispatch(_acceptRequestSuccess(fulfillment))
})
.then(() => {
this.props.dispatch(navigatePop());
})
.catch(err => {
console.log(err);
this.props.dispatch(_acceptRequestError(error))
})
}
But if you still want to return a promise you can make the function inside the action return the promise:
export function acceptRequest(requestId,fulfilledBy){
return dispatch => {
return fulfillments.create(requestId,fulfilledBy)
.then(response => response.json())
.then(fulfillment => {
dispatch(_acceptRequestSuccess(fulfillment))
})
.catch(err => {
console.log(err);
dispatch(_acceptRequestError(error))
})
}
}

Resources