How do you save/post using axios correctly - reactjs

I using Spring boot has backend and react-redux has frontend. The problem is where I try too save my data to my db the first click just save my first entity out of seven. After the second click it works normal and afterwards it works normal. I have try useEffect still the same problem.
export const setChecklist = (Checklist) => {return (dispatch) => {
console.log(Checklist);
axios
.post("http://localhost:8081/api/checklist/addList", Checklist)
.then((response) => {
console.log(response);
dispatch({
type: SET_CHECKLIST,
payload: response.data,
});
})
.catch((error) => {
console.log(error);
});
};
};

try this code:
export const setChecklist = async (Checklist) => {
const response = await axios
.post("http://localhost:8081/api/checklist/addList", Checklist)
.then((response) => {
console.log(response);
dispatch({
type: SET_CHECKLIST,
payload: response.data,
});
})
.catch((error) => {
console.log(error);
});
}
useEffect(() => {
setChecklist ()
.then((res) => {
setChecklist(res)
})
.catch((e) => {
console.log(e)
})
}, [])

Related

run useEffect an other time when my function is called

I'm using useEffect to get all that I want from my backEnd,
When an onChange event is triggered, I call my function checkHandler method, where I make a post request to my backend. But the Get that I do first is not actualized, and the only way that I found to show the good stuff is to reload the page :s I think there is a better way to do it if my useEffect renders another time, but I don't know how to do it
const [message, setMessage] = useState([]);
useEffect(() => {
axios
.get(getAllMessage, config)
.then((res) => {
setMessage(res.data);
console.log("mounted");
})
.catch((err) => {
console.log(err);
});
}, []);
const checkHandler = (e) => {
let item = e.target.closest("[data-id]");
const disLikeMessage = `http://localhost:3001/api/like/dislike/${item.dataset.id}`;
const likeMessage = `http://localhost:3001/api/like/${item.dataset.id}`;
if (!item.checked) {
console.log("unchecked");
axios
.post(disLikeMessage, {}, config)
.then((res) => {})
.catch((err) => {
console.log(err);
});
} else {
console.log("checked");
axios
.post(likeMessage, {}, config)
.then((res) => {})
.catch((err) => {
console.log(err);
});
}
};
You don't need to refresh useEffect as there is no concept to refresh useEffect
Create a method that will fetch your all messages
const fetchMessages = () => {
axios
.get(getAllMessage, config)
.then((res) => {
setMessage(res.data);
console.log("mounted");
})
.catch((err) => {
console.log(err);
});
};
Inside your useEffect callback just call this fetchMessages()
useEffect(() => {
fetchMessages();
}, []);
Here is your checkHandler()
const checkHandler = (e) => {
let item = e.target.closest("[data-id]");
const disLikeMessage = `http://localhost:3001/api/like/dislike/${item.dataset.id}`;
const likeMessage = `http://localhost:3001/api/like/${item.dataset.id}`;
fetchMessages(); // Call fetchMessages wherever you need to fetch all messages
if (!item.checked) {
console.log("unchecked");
axios
.post(disLikeMessage, {}, config)
.then((res) => {})
.catch((err) => {
console.log(err);
});
} else {
console.log("checked");
axios
.post(likeMessage, {}, config)
.then((res) => {})
.catch((err) => {
console.log(err);
});
}
};

Sequential Call of API in React and Redux

I need to upload multiple images but I also need to upload them one by one.
I wanted to upload them sequentially. First, you need to wait for the previous API response before calling another API response. How will I do it?
Currently is that I'm calling them in parallel. Whoever upload image API response has finished first, will be displayed.
export const uploadPhotos =
({ photos, size, controller }) =>
async (dispatch) => {
await Promise.all(
photos.forEach(async (photo, index) => {
const formData = new FormData();
formData.append("photo", photo);
dispatch({ type: constants.UPLOAD_PHOTOS_START, size });
try {
const response = await axios.post(
`${API_URL}/photos/upload`,
formData,
{
onUploadProgress({ loaded, total }) {
dispatch(setUploadProgress({ id: index, loaded, total }));
},
signal: controller.signal,
}
);
dispatch({
type: constants.UPLOAD_PHOTOS_SUCCESS,
payload: response.data,
});
} catch (error) {
dispatch({
type: constants.UPLOAD_PHOTOS_FAILURE,
payload: error,
});
}
})
);
};
export const setUploadProgress = (progress) => ({
type: constants.SET_UPLOAD_PROGRESS,
payload: progress,
});
export const resetUploadData = () => ({
type: constants.RESET_UPLOAD_DATA,
});
export const setOverallSize = (data) => ({
type: constants.SET_OVERALL_SIZE,
payload: data,
});
First: await Promise.all(photos.forEach(async () => {})) will have no effect.
forEach does not return a value so you want .map instead.
But for sequential calls, something like this is preferred:
export const uploadPhotos =
({ photos, size, controller }) =>
async (dispatch) => {
for (const [index, photos] of photos.entries()) {
const formData = new FormData();
formData.append("photo", photo);
dispatch({ type: constants.UPLOAD_PHOTOS_START, size });
try {
const response = await axios.post(
`${API_URL}/photos/upload`,
formData,
{
onUploadProgress({ loaded, total }) {
dispatch(setUploadProgress({ id: index, loaded, total }));
},
signal: controller.signal,
}
);
dispatch({
type: constants.UPLOAD_PHOTOS_SUCCESS,
payload: response.data,
});
} catch (error) {
dispatch({
type: constants.UPLOAD_PHOTOS_FAILURE,
payload: error,
});
}
}
};

resolving race condition on API call

I'm having a problem that seems to be due to an async call. I have an action that makes an API call and pushes to a Dashboard page. That API call also updates state.account.id based on the response it gives back:
const submitLogin = e => {
e.preventDefault();
props.loginAndGetAccount(credentials);
props.history.push('/protected');
e.target.reset();
}
loginAndGetAccount is coming from this action:
export const loginAndGetAccount = credentials => dispatch => {
dispatch({ type: GET_ACCOUNT_START })
axios
.post('https://foodtrucktrackr.herokuapp.com/api/auth/login/operators', credentials)
.then(res => {
console.log(res);
dispatch({ type: GET_ACCOUNT_SUCCESS, payload: res.data.id })
localStorage.setItem("token", res.data.token)
})
.catch(err => console.log(err));
}
On the Dashboard page, I have useEffect set up to make another API call dynamically based on the value held in state.account.id. However, it seems the first API call is pushing to the Dashboard page before the response comes back and updates state.account.id. Therefore, when the second API call is made there, it's passing state.account.id to that dynamic API call as undefined, which, of course, results in a failed call. How can I resolve this?
Here's what's happening:
const Dashboard = props => {
const [accountInfo, setAccountInfo] = useState({});
useEffect(() => {
console.log(props.accountId);
axiosWithAuth()
.get(`/operator/${props.accountId}`)
.then(res => {
console.log(res);
})
.catch(err => console.log(err));
}, [])
return (
<div>
<h1>This is the Dashboard component</h1>
</div>
)
}
const mapStateToProps = state => {
return {
accountId: state.account.id
}
}
export default connect(mapStateToProps, {})(Dashboard);
The root of the problem is that you are making a request here, but not
export const loginAndGetAccount = credentials => dispatch => {
dispatch({ type: GET_ACCOUNT_START })
axios
.post('https://foodtrucktrackr.herokuapp.com/api/auth/login/operators', credentials)
.then(res => {
console.log(res);
dispatch({ type: GET_ACCOUNT_SUCCESS, payload: res.data.id })
localStorage.setItem("token", res.data.token)
})
.catch(err => console.log(err));
}
waiting for it to complete here before you navigate to the next page
const submitLogin = e => {
e.preventDefault();
props.loginAndGetAccount(credentials);
props.history.push('/protected');
e.target.reset();
}
the quickest way to fix this is to returnt the promise from loginAndGetAccount and then props.history.push in the resolution of that promise...
like this:
export const loginAndGetAccount = credentials => dispatch => {
dispatch({ type: GET_ACCOUNT_START })
// return the promise here
return axios
.post('https://foodtrucktrackr.herokuapp.com/api/auth/login/operators', credentials)
.then(res => {
console.log(res);
dispatch({ type: GET_ACCOUNT_SUCCESS, payload: res.data.id })
localStorage.setItem("token", res.data.token)
})
.catch(err => console.log(err));
}
...
const submitLogin = e => {
e.preventDefault();
props.loginAndGetAccount(credentials)
.then(() => {
// so that you can push to history when it resolves (the request completes)
props.history.push('/protected');
e.target.reset();
}
.catch(e => {
// handle the error here with some hot logic
})
}

Reducer not called after action return?

Here's my login action code. What am I doing wrong ? As you can see, reducer state update not called.
Please, help me guys!
React - 16.8
Axios Http Client
Node & Mongo Db Backend
export const loginUser = (userData) => {
axios.post(URL + '/api/admin/login', userData)
.then(res => {
return {
type: SIGNIN_USER,
payload: storeData
}
})
.catch(err => {
return {
type: SHOW_MESSAGE,
payload: err.response.data
}
});
};
.then(res => {
return {
type: SIGNIN_USER,
payload: storeData
}
})
Instead of returning res, apply an action to it here. You mentioned changing the state, so something similar:
.then(res => {
this.state.someResult = res;
})
You need to dispatch the action, not just return the object:
const dispatch = useDispatch(); // Assuming you're inside functional component
export const loginUser = (userData) => {
axios.post(URL + '/api/admin/login', userData)
.then(res => {
return dispatch({
type: SIGNIN_USER,
payload: storeData
})
})
.catch(err => {
return dispatch({
type: SHOW_MESSAGE,
payload: err.response.data
})
});
};
Try with this code sample :
export const loginUser = userData => dispatch => (
axios.post(URL + '/api/admin/login', userData)
.then(res => dispatch({ type: SIGNIN_USER, payload: res }))
.catch(err => dispatch({ type: SHOW_MESSAGE, payload: err.response.data }))
)
Make use of Arrow functions it improves the readability of code. No need to return anything in API.fetchComments, Api call is asynchronous when the request is completed then will get the response, there you have to just dispatch type and data.
Below code does the same job by making use of Arrow functions.
export const bindComments = postId => {
return dispatch => {
API.fetchComments(postId).then(comments => {
dispatch({
type: BIND_COMMENTS,
comments,
postId
});
});
};
};
reference link : React-Redux: Actions must be plain objects. Use custom middleware for async actions

Cannot read property `.then` of undefined with axios and react in actions

I am using axios in an action and trying to call that action with a chaining action. I will show what I am trying to do here:
this.props.fetchOffers().then(() => {
this.props.filter(this.props.filterOption);
});
But I get an error: Cannot read property 'then' of undefined.
What I do not get is that right below this function I have another action that is doing this exact same thing and working just fine.
this.props.sortOffers(value).then(() => {
this.props.filter(this.props.filterOption);
});
Here is a working version of this.
Here is the actions file:
import axios from 'axios';
import { reset } from 'redux-form';
import { FETCH_OFFERS, SORT_OFFERS, FETCH_OFFER, GET_FILTER, PAYMENT_TYPE } from './types';
export function paginateOffers(indexPosition, numberOfItems) {
return (dispatch) => {
axios
.get('/API/offers/pagination', {
params: {
position: indexPosition,
number: numberOfItems,
},
})
.then((response) => {
dispatch({ type: FETCH_OFFERS, payload: response.data });
})
.catch((error) => {
console.error(error);
});
};
}
export function fetchOffers() {
return dispatch => {
axios
.get('/API/offers')
.then((response) => {
dispatch({ type: FETCH_OFFERS, payload: response.data });
})
.catch((err) => {
console.error(err);
});
};
}
export function fetchOffer(id) {
return (dispatch) => {
axios
.get(`/API/offers/${id}`)
.then((response) => {
dispatch({ type: FETCH_OFFER, payload: response.data.result });
})
.catch((err) => {
console.error(`ERROR: ${err}`);
});
};
}
export function sortOffers(params) {
const { price, title, category, type } = params;
return dispatch =>
axios
.get('/API/offers/sort', {
params: { price, title, category, type },
})
.then((response) => {
dispatch({
type: SORT_OFFERS,
payload: response.data,
sortOptions: params,
});
dispatch({
type: PAYMENT_TYPE,
payment: type,
});
dispatch(reset('sorter'));
})
.catch((err) => {
console.error(err);
});
}
export function getFilterOption(option) {
return (dispatch) => {
dispatch({
type: GET_FILTER,
option,
});
};
}
You aren't returning a promise in your fetchOffers action creator. Notice the subtle difference in how you've declared your fat-arrow function.
Try this:
export function fetchOffers() {
return dispatch =>
axios
.get('/API/offers')
.then((response) => {
dispatch({ type: FETCH_OFFERS, payload: response.data });
})
.catch((err) => {
console.error(err);
});
}

Resources