run useEffect an other time when my function is called - reactjs

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);
});
}
};

Related

How do you save/post using axios correctly

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)
})
}, [])

useEffect: How to put data in the state in order

I'd like to ask how to retrieve data through use Effect.
The flow I want is as follows.
First, I want to get the 'cards' state, fill the cards with data, and then fill the data through the cardsPromises after that.
But my code couldn't get cards and wordAll, and the empty value came out.
I think it's because the cards are still empty, but I don't know how to operate in order.
Please tell me how to do it.
const [wordAll, setWordAll] = useState([]);
const [cards, setCards] = useState([]);
useEffect(() => {
axios
.get("http/api/words/", {
headers: {
Authorization: cookies.token,
},
})
.then((response) => {
setCards(response.data);
})
.catch((error) => {
console.log(error);
});
const cardsPromises = cards.map((contents) =>
axios.get(
`http/api/words/detail_list/?contents=${contents.contents}`,
{
headers: {
Authorization: cookies.token,
},
}
)
);
console.log("cards", cards);
Promise.all(cardsPromises)
.then((response) => {
console.log("resp", response.data);
setWordAll(response.data);
})
.catch((error) => {
console.log("err==>", error);
});
}, []);
You are correct, cards array is still empty in the useEffect callback when the fetching the data. I suggest converting to async/await and waiting for the first fetch to resolve and using that value of cards for the fetching of the rest of the data.
const [wordAll, setWordAll] = useState([]);
const [cards, setCards] = useState([]);
useEffect(() => {
const fetchData = async () => {
try {
const{ data: cards } = await axios.get(
"http/api/words/",
{
headers: {
Authorization: cookies.token,
},
},
);
setCards(cards);
const cardsPromises = cards.map((contents) =>
axios.get(
`http/api/words/detail_list/?contents=${contents.contents}`,
{
headers: {
Authorization: cookies.token,
},
}
);
);
const wordAllResponse = await Promise.all(cardsPromises);
const wordAll = wordAllResponse.map(({ data }) => data);
setWordAll(wordAll);
} catch (error) {
// handle any errors, rejected Promises, etc..
}
};
fetchData();
}, []);
Wrap your 2nd axios call inside a function, and call it after 1st axios call returns.
useEffect(() => {
const getWords = (cards) => {
const cardsPromises = cards.map((contents) =>
axios.get(
`http/api/words/detail_list/?contents=${contents.contents}`,
{
headers: {Authorization: cookies.token}
}
)
);
Promise.all(cardsPromises)
.then((response) => {
setWordAll(response.data);
})
.catch((error) => {
console.log("err==>", error);
});
})
axios
.get("http/api/words/", {
headers: { Authorization: cookies.token },
})
.then((response) => {
const cards = response.data;
setCards(cards);
getWords(cards);
})
.catch((error) => {
console.log(error);
});
}, [])
Now dependency chain is clearer.

async function in react component isn't working when triggered from the axios request

network.services.js
axiosCall = (axiosURL) => {
// const axiosURL = "https://api.github.com/user"
axios.get(axiosURL, {
headers: {
'Authorization': `qwdvryjutmnevw`,
}
}).then((res) => {
console.log(res.data);
return res.data;
}).catch((error) => {
throw error.message;
// console.error(error);
// toast.error(error.message);
})
}
component.js
const getData = async () => {
const asyncExample = async () => {
const result = await networkServices.axiosCall("/api/v1/calendars");
const responseData = await result;
console.log(responseData);
return responseData;
}
const data = asyncExample()
data.then(function(result) {
console.log(result); // "Some User token"
})
}
Trying to get data from service to my component in const result, console form service is consoling data but component is always returning undefined instead of data from the service file. SetTimeout function is also not working in component.
You have many mistakes. I advise you to take a look at documentation about Promises
First one:
You don't return data in axiosCall
A way to return data:
axiosCall = (axiosURL) => new Promise((resolve, reject) => {
axios.get(axiosURL, {
headers: {
'Authorization': `yourTokenHere`,
}
}).then((res) => {
// return a response data
resolve(res.data);
}).catch((error) => {
// return only error message
reject(error.message);
})
})
to use axiosCall:
try {
// don't forgot to configure axios with base url
const data = await axiosCall('/api/v1/calendars');
// do something with your data
} catch (e) {
// do something with error message
console.log(e);
}
Second:
Your make mistakes when call async function
Look at this example:
const getData = () => {
networkServices
.axiosCall("/api/v1/calendars")
.then(function(result) {
// when promise resolve
console.log(result);
})
.catch(error => {
// when promise reject
console.log(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
})
}

Axios get inside a .then is not working as intended

I am using axios to make a http request. Inside the .then() i am using another axios call. Finally, I have a third then() which is supposed to run after the second then but it is actually not doing so.
let assets = [];
export const initAssets = () => {
return dispatch => {
dispatch(setLoadingToTrue());
axios.get('https://....json')
.then(response => {
for(let key in response.data) {
assets.push(response.data[key]);
}
})
.then(() => {
const token = '...';
assets.forEach((cur) => {
axios.get('...' + cur.ticker + '/quote?token=' + token)
.then(response => {
console.log(response);
cur.price = response.data.latestPrice;
})
})
})
.then(() => {
dispatch(initAllAssets(assets));
dispatch(setLoadingToFalse());
})
.catch(error => {
console.log(error);
dispatch(setLoadingToFalse());
})
}
}
The dispatch on the last .then are being executed before the axios request in the second then is completed. How can I make the last then run only after the second axios request is completed?
You can make use of Promise.all to return the response to next .then block and it will be called once all the promises have resolved in the second .then
let assets = [];
export const initAssets = () => {
return dispatch => {
dispatch(setLoadingToTrue());
axios.get('https://....json')
.then(response => {
for(let key in response.data) {
assets.push(response.data[key]);
}
})
.then(() => {
const token = '...';
const promises = [];
assets.forEach((cur) => {
promises.push(axios.get('...' + cur.ticker + '/quote?token=' + token)
.then(response => {
console.log(response);
cur.price = response.data.latestPrice;
}))
})
return Promise.all(promises);
})
.then(() => {
dispatch(initAllAssets(assets));
dispatch(setLoadingToFalse());
})
.catch(error => {
console.log(error);
dispatch(setLoadingToFalse());
})
}
}

Resources