dispatching Asynchronous action from an array react redux thunk - javascript

As per the requirement we need to make API call from the array list.Have used redux-thunk for async operation.Having issues while passing the request parameter to the reducer after api call is finished.
# From the container
let document = [ bankstatement1,bankstatement2];
document.map(element => {
dispatch ( actions.uploadFiles(element) )
});
# inside actions
export const uploadFiles = (payload) => {
return async dispatch => {
const response = await callAPIMiddleware(dispatch, {
types: ['DOC_UPLOAD_START','DOC_UPLOAD_SUCCESS','DOC_UPLOAD_ERROR'],
endPoint: ApiEndpoints.DOCUMENT_UPLOAD,
type: HTTP_METHOD_TYPE.POST,
payload: payload,
headers: Headers.multipart,
});
return response;
};
};
# inside axios middle ware
export const callAPIMiddleware = async (dispatch, RequestParams) => {
# calling upload_start ,here also the request payload being asked.
dispatch({
type: "DOC_UPLOAD_START,
data:RequestParams //bankstatement1,bankstatement2
});
# let res = await axios.post(endPoint,RequestParams, {
headers: reqHeaders,
config: reqConfig,
});
if (res && res.data) {
dispatch({
type:'DOC_UPLOAD_SUCCESS',
data: res.data,
param:RequestParams //bankstatement2,bankstatement2 here it is always referring to "bankstatement2"
});
}
After the API call is finished, reference to first request parameter is overridden by second one.Can anyone suggest how we can still refer to the first element .

EDITED:
what if you try to place the last piece of logic in "then" so it surely scoped there?
axios.post(endPoint,RequestParams, {
headers: reqHeaders,
config: reqConfig,
}).then(res => {
console.log('calling dispatch for ', RequestParams);
if (res && res.data) {
dispatch({
type:'DOC_UPLOAD_SUCCESS',
data: res.data,
param: RequestParams,
});
} else {
console.log('oops no result for ', RequestParams);
}
})

Related

RTK query and response from server

updateTagCurrentValue: builder.mutation<any, {path: string, body: updateTagCurrentValueBody}>({
query: (args) => {
const {path, body} = args
return ({
url: `/v2/tags/${path}/values/current`,
method: 'PUT',
body: body,
})
},
transformResponse: (response) => {
return response
}
})
I am new in RTK, this mutation is working well, but I can not understand how to get a response from server? I see it in inspect network tab, I see my added data in the server, but the response comes null
const [updateTagCurrentValue, {error, isSuccess}] = useUpdateTagCurrentValueMutation()
const onSubmit: SubmitHandler = async (data) => {
let body: updateTagCurrentValueBody = {
value: {value: JSON.stringify(data)}
}
try {
let response = await updateTagCurrentValue({path: 'test', body}).unwrap();
console.log(response)
} catch (err) {
console.log(err)
}
}
I searched for solutions, and some people said add .unwrap() at the end of the call, but it didn't help. transformResponse also changes nothing, isSuccess changes from false to true after the second submission...

React/Redux - Dispatch method - returning error

I'm currently trying to add and delete my items on the page and it's returning an error.
Unhandled rejection (TypeError): Cannot read property data of undefined pointing to .catch in both of in the below code.
export const addItem = (item) => (dispatch,
getState) => {
axios
.post('/api/items', item, tokenConfig(getState))
.then(res => dispatch({
type: ADD_ITEM,
payload: res.data
}))
.catch(err => dispatch(returnErrors(err.response.data, err.response.status))
);
};
export const deleteItem = (id) => (dispatch, getState) => {
axios
.delete(`/api/items/${id}`, tokenConfig(getState))
.then(res => dispatch({
type: DELETE_ITEM,
payload: id
}))
.catch(err => dispatch(returnErrors(err.response.data, err.response.status))
);
};
/////////////////////////////////////////////////
The returnErrors method referenced above is from another file that is here:
import { GET_ERRORS, CLEAR_ERRORS } from './types';
// RETURN ERRORS
export const returnErrors = (msg, status, id = null) => {
return {
type: GET_ERRORS,
payload: { msg, status, id }
};
};
// CLEAR ERRORS
export const clearErrors = () => {
return {
type: CLEAR_ERRORS
};
};
I have put a console.log(err.response) and a console.log(err.response.data) right above the dispatch(returnErrors(err.response.data, err.response.data)); and returned undefined for the first and uncaught (in promise) cannot read property of undefined
I was told by someone that
This essentially means your error object doesn't have correct data. Please look into the error object returned. It could be an issue with items/user api, it should return correct error object.
items api route
router.post('/', auth, (req, res) => {
const newItem = new Item({
name: req.body.name
})
newItem.save().then(item => res.json(item));
});
// DELETE api/items/:id
// Delete an item
// Private
router.delete('/:id', auth, (req, res) => {
Item.findById(req.params.id)
.then(item => item.remove().then(() => res.json({ deleted: true
})))
.catch(err => res.status(404).json({ deleted: false }));
})
Not sure where data is undefined. Anyone see anything missing?
You can take a look at what the chrome dev tools network tab returned here:
https://imgur.com/D5OGLpf
authActions
// Check token & Load User
// Want to check routes/auth.js for user by id that's included with token
// Going to use asynchronous request, use dispatch
export const loadUser = () => (dispatch, getState) => {
// User loading
dispatch({ type: USER_LOADING });
// Fetch user
axios.get('/api/auth/user', tokenConfig(getState))
.then(res => dispatch({
type: USER_LOADED,
payload: res.data
}))
.catch(err => {
dispatch(returnErrors(err.response.data, err.response.status));
dispatch({
type: AUTH_ERROR
});
});
};
// Register User
export const register = ({ name, email, password }) => dispatch => {
// Headers
const config = {
headers: {
'Content-Type': 'application/json'
}
}
// Request body
const body = JSON.stringify({ name, email, password });
axios.post('/api/users', body, config)
.then(res => dispatch({
type: REGISTER_SUCCESS,
payload: res.data
}))
.catch(err => {
dispatch(returnErrors(err.response.data, err.response.status, 'REGISTER_FAIL'));
dispatch({
type: REGISTER_FAIL
});
});
};
// LogIn
export const login = ({ email, password }) => dispatch => {
// Headers
const config = {
headers: {
'Content-Type': 'application/json'
}
}
// Request body
const body = JSON.stringify({ email, password });
axios.post('/api/auth', body, config)
.then(res => dispatch({
type: LOGIN_SUCCESS,
payload: res.data
}))
.catch(err => {
dispatch(returnErrors(err.response.data, err.response.status,
'LOGIN_FAIL'));
dispatch({
type: LOGIN_FAIL
});
});
};
// LogOut
export const logout = () => {
return {
type: LOGOUT_SUCCESS
};
};
// Setup config/headers and Token
export const tokenConfig = (getState) => {
// Get token from localstorage
const token = getState().auth.token;
// Headers
const config = {
headers: {
"Content-type": "application/json"
}
}
// Check if token exists, add to Headers
if(token) {
config.headers['x-auth=token'] = token;
}
return config;
}
Base your image https://imgur.com/D5OGLpf, your request to axios.delete('/api/items/${id} do not reach the route /api/items/:id.
Why I said so?
The response status is 401 (https://imgur.com/D5OGLpf), meaning that Unauthorized. The endpoint of the route router.delete('/:id' might be protected by the authentication middleware or something like that.
To solve it,
First
You need to make an authenticated request using the way you set up for your api either basic authentication, oauth[2], or your customized one.
Then
Before dispatch dispatch(returnErrors..., you need to check if the data exists.
axios
.delete(`/api/items/${id}`, tokenConfig(getState))
.then(res => dispatch({
type: DELETE_ITEM,
payload: id
}))
.catch(err => {
if(error.status === 404) {
// here, you are sure that error.response.data exists
dispatch(returnErrors(err.response.data, err.response.status)
}
else {
// do something else to handle the error
}
})
**Remember that ** the caught error can be anything ranging from your error status 400, 500,... to you un-caught error within the .then(...).
The inner promise to remove the item remains in a pending state and as you have noted doesn't return any response.
To have an idea what is happening.
Item.findById(req.params.id)
.then(item => item.remove().then(() => res.json({ deleted: true
})))
.catch(err => res.status(404).json({ deleted: false }));
})
can be simplified to
P.then(p => Q)
where P and Q are promises objects.
When P is fulfilled, it returns Q and Q continues to remain in a pending state waiting for it to be resolved.
You can resolve Q by flattening the then chain to handle when the remove operation is fulfilled.
Item.findById(req.params.id)
.then(item => item.remove())
.then(() => res.json({ deleted: true }))
.catch(err => res.status(404).json({ deleted: false }));

I can't get this React action's return statement to run

The following code is a React action that is supposed to dispatch to a reducer. I can't seem to get the return statement to run. I can get it to hit a debugger right blelow the data variable declaration, but that's it. If I try to run the rest of the code within debugger, I'm getting a reference error "Return is not a function". I can't figure out what I'm missing here. Any help would be greatly appreciated. Thanks in advance.
const baseUrl = 'http://localhost:3001'
export const signUp = (user) => {
let data = {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({ user })
}
return dispatch => {
fetch(`${ baseUrl }/signup`, data)
.then(response => response.json())
.then(user => {
sessionStorage.setItem('user', user)
dispatch({
type: 'SET_USER',
payload: user.current
})
})
.catch(err => err)
}
}
Well if you are using redux-thunk you are missing the parameters inside for your function and currently you have just user. Try this:
export const signUp = (dispatch, getState, user) => {
...your code
}

AsyncStorage await issue with redux and axios

I need to send an axios request passing a token, this token is saved on my AsyncStorage. The problem is, when i make the call looks like its been sended without the AsyncStorage return the token, also the then/catch do not trigger.
Code example:
export const verificarPreco = (produto, estabelecimento) => {
return async dispatch => {
axios({
method: "get",
url: `${API}preco/verificarPreco/?produto=${produto}&estabelecimento=${estabelecimento}`,
headers: {
"x-access-token": await AsyncStorage.getItem("#Offer4All:token")
}
})
.then(response => {
verificarPrecoSucesso(response.data, dispatch);
})
.catch(error => {
verificarPrecoErro(error.response, dispatch);
});
};
};
You could use just async/await instead of handling the promises manually, and putting a try/catch around that.
export const verificarPreco = (produto, estabelecimento) => {
return async dispatch => {
try {
const token = await AsyncStorage.getItem("#Offer4All:token");
const request = await axios({
method: "get",
url: `${API}preco/verificarPreco/?produto=${produto}&estabelecimento=${estabelecimento}`,
headers: {
"x-access-token": token
}
});
const response = await request.json();
verificarPrecoSucesso(response.data, dispatch);
} catch (error) {
verificarPrecoErro(error.response, dispatch);
}
};
};

localstorage.getitem('key') sometimes returns null - in a react app

this is a very weird problem! I'm trying to build a login form which sets a JWT token in localstorage. Other forms then use that token to post requests. I can see the token in my console.log just fine, but sometimes (like 3 out of 5 times), when I am setting localstorage.getitem('idToken'), it shows as null. This behavior most noticeably happens when I remove the console.log(idToken) from my loginUser() function (code in actions.js file - given below). What am I doing wrong? my app is built using React/Redux.
action.js
export function loginUser(creds) {
const data = querystring.stringify({_username: creds.username, _password: creds.password});
let config = {
method: 'POST',
headers: { 'Content-Type':'application/x-www-form-urlencoded' },
body: data
};
return dispatch => {
// We dispatch requestLogin to kickoff the call to the API
dispatch(requestLogin(creds));
return fetch(BASE_URL+'login_check', config)
.then(response =>
response.json().then(user => ({ user, response }))
).then(({ user, response }) => {
if (!response.ok) {
// If there was a problem, we want to
// dispatch the error condition
dispatch(loginError(user.message));
return Promise.reject(user)
} else {
localStorage.setItem('idToken', user.token);
let token = localStorage.getItem('idToken')
console.log(token);
// if I remove this log, my token is returned as null during post.
dispatch(receiveLogin(user));
}
}).catch(err => console.log("Error: ", err))
}
}
here's my POST request:
import axios from 'axios';
import {BASE_URL} from './middleware/api';
import {reset} from 'redux-form';
let token = localStorage.getItem('idToken');
const AuthStr = 'Bearer '.concat(token);
let headers ={
headers: { 'Content-Type':'application/json','Authorization' : AuthStr }
};
export default (async function showResults(values, dispatch) {
console.log(AuthStr);
axios.post(BASE_URL + 'human/new', values, headers)
.then(function (response) {
console.log(response);
alert("Your submit was successful");
//dispatch(reset('wizard'));
}).catch(function (error) {
console.log(error.response);
alert(error.response.statusText);
});
});
This GET request works everytime, BTW:
getHouses = (e) => {
let token = localStorage.getItem('idToken') || null;
const AuthStr = 'Bearer '.concat(token);
axios.get(BASE_URL + 'household/list', { headers: { Authorization: AuthStr } }).then((response) =>
{
let myData = response.data;
let list = [];
let key =[];
for (let i = 0; i < myData._embedded.length; i++) {
let embedded = myData._embedded[i];
list.push(embedded.friendlyName);
key.push(embedded.id);
}
this.setState({data: list, key: key});
})
.catch((error) => {
console.log('error' + error);
});
}
I'm at my wit's end! Please help!
The localStorage.setItem() is a asynchronous task, and sometimes you run let token = localStorage.getItem('idToken') just after the setItem will fail, so you get a null, so please put the getItem operation some later, have a try, it will be different :
setTimeout(function() {
let token = localStorage.getItem('idToken');
dispatch(receiveLogin(user));
}, 50);
Move your token logic (i.e. localStorage.getItem('idToken');) inside the exported function and it should work
export default (async function showResults(values, dispatch) {
let token = localStorage.getItem('idToken');
const AuthStr = 'Bearer '.concat(token);
let headers ={
headers: { 'Content-Type':'application/json','Authorization' : AuthStr
}
};
axios.post(BASE_URL + 'human/new', values, headers)...
There can't be a case where you set a key value in localstorage and then it returns you null, immediately in the next line.
localStorage.setItem('idToken', user.token);
let token = localStorage.getItem('idToken');
This will only happen if your user.token value is null.
Maybe the case here is your thennable function not returning value to your next then like this:
....
.then(response =>
// return response to your next then function
// this will be passed to next then function as params
return response.json();
).then(({ user, response }) => {
....
Make a function whose return the value or a default value
const [hideTyC, setHideTyC] = useState(false);
const loadTyCFlag = (): any => {
if (
localStorage.getItem("tyc") !== null ||
localStorage.getItem("tyc") !== undefined
) {
return localStorage.getItem("tyc") || false;
}
};
useIonViewDidEnter(() => {
hideTabBar();
setHideTyC(loadTyCFlag());
});

Categories

Resources