I have 2 axios functions, one is to return a list of currency names and the other is to get the value of the said currencies. I need to get corresponding value of the currency unto a hook.
[currencies, setCurrencies] = useState([]);
getCurrencyNames = () =>
axios({
method: `get`,
url: `${url}/getCurrencies`
}).then(r =>
setCurrencies(r.data.map(currency => {
return {
name: currency,
value: getCurrencyValue(currency)
}
}))
);
getCurrencyValue = async (currency) => {
const data = await axios({
method: `get`,
url: `${url}/getValue/?from=PHP&to=${currency}`
}).then(r => r.data)
return data;
}
what should return is the currencies hook being filled with objects such as this:
{
name: "USD",
value: 0.020
}
but the objects returned like this:
{
name: "USD",
value: Promise
}
I've also tried setting the hook into the getCurrencyValue like this:
getCurrencyValue = async (currency) => {
axios({
method: `get`,
url: `${url}/getValue/?from=PHP&to=${currency}`
}).then(r =>
setCurrencies([
...currencies,
name: currency,
value: r.data
])
)
}
but what happens is that only the last one is set inside the hook
import { useEffect, useState } from "react";
import axios from "axios";
function App() {
const [currencies, setCurrencies] = useState([]);
async function getCurrencyValue(post) {
const data = await axios({
method: `get`,
url: `https://jsonplaceholder.typicode.com/users`
}).then((r) => ({
post,
user: r.data
}));
return data;
}
function getCurrencyNames() {
return axios({
method: `get`,
url: `https://jsonplaceholder.typicode.com/posts`
}).then((r) => {
const res = Promise.all(
r.data.map(async (currency) => {
return {
name: currency,
value: await getCurrencyValue(currency)
};
})
);
return res;
});
}
useEffect(() => {
(async function () {
const data = await getCurrencyNames();
console.log(data);
console.log("fetched in useEffect");
setCurrencies(data);
})();
}, []);
return <></>;
}
export default App;
Here is the link https://codesandbox.io/s/condescending-germain-8ie8j?file=/src/App.js
Note: See in the console
It is normal that it return a promise, you have to resolve it by puting await befor the call and make the map function async:
getCurrencyNames = () =>
axios({
method: `get`,
url: `${url}/getCurrencies`
}).then(r =>
setCurrencies(r.data.map(async currency => {
return {
name: currency,
value: await getCurrencyValue(currency)
}
}))
);
Related
I make getStaticProps in pages, in local it's work but in production doesn't work. my code is below:
import {GetStaticProps} from 'next';
export const getStaticProps: GetStaticProps = async () => {
const res = await apiAboutV2();
const data = res ?? {};
return {
props: {about: _.result(data, 'data', {})},
revalidate: true,
};
};
interface Props {
about: any;
}
export default function About({about}: Props) {
return (
<div>
{about?.history}
</div>
)
}
anyone can suggestion for me?
edit:
export const apiAboutV2 = async () => {
const uri = `${baseUrl}/api/v2/public/about`;
const res = await axios({
method: 'GET',
url: uri,
})
.then((res) => res.data)
.catch((err) => err?.response?.data || err);
return res;
};
code above is apiAboutV2
I have the following fetchData async function returning a message froma lambda function I want to take that response and dump it onto my page I am using the react-hooks-async package, with a useEffect inside of it. However when I start the function isnide the useAsyncTask it just contiunally runs and never gets the result. I could do it if I hooked up a button to the start() function and it would display correct, but I want it to run on load.
I am using Gatsby JS and react
var fetchData = async function run() {
const response = await fetch(fetchUrl, {
method: "post",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
customer_id: parsed.session_id,
}),
})
.then(res => {
return res.json()
})
.catch(error => console.log(error))
console.log(response)
return response
}
const Customer = () => {
const { start, started, result } = useAsyncTask(fetchData)
useEffect(() => {
console.log("result")
console.log(result)
console.log("result ends")
start()
}, [result])
return (
<div>
{started && "Fetching..."}
<div>Name: {result && result.message.customer_id}</div>
</div>
)
}
I was over engineering it. All that was required was the following
fetchData().then(value => console.log(value))
const Test = () => {
const [data, setData] = useState("")
useEffect(() => {
fetchData().then(test => {
setData(test)
})
}, [])
return data && <p>{data.message.customer_id}</p>
}
I use React Redux and I create a function to login, but I need to get a callback return after successfull login and redirect user to a page.
I try to passing function as parameter but not working.
How can I get the return after dispatch action?
Login fun
export const login = (request,cb) => {
return dispatch => {
let url = "/api/user/login";
axios({
method: "post",
url: url,
data: request,
config: { headers: { "Content-Type": "multipart/form-data" } }
})
.then(response => {
let authState = {
isLoggedIn: true,
user: response.data
};
cb();
window.localStorage["authState"] = JSON.stringify(authState);
return dispatch({
type: "USER_LOGIN_FULFILLED",
payload: { userAuthData: response.data }
});
})
.catch(err => {
return dispatch({
type: "USER_LOGIN_REJECTED",
payload: err
});
});
};
};
submiting
handleLogin(e) {
this.setState({ showLoader: true });
e.preventDefault();
const request = new Object();
if (this.validator.allValid()) {
request.email = this.state.email;
request.password = this.state.password;
this.props.login(request, () => {
//get callbach here
this.props.history.push('/my-space/my_views');
})
this.setState({ showLoader: false });
} else {
this.setState({ showLoader: false });
this.validator.showMessages();
this.forceUpdate();
}
}
const mapStateToProps = state => {
return {
authState: state
};
};
const mapDispatchToProps = dispatch => {
return {
login: request => dispatch(login(request))
};
};
export default connect(mapStateToProps, mapDispatchToProps)(LoginForm);
The cb is missing in your connect(...)
Here is the fix
handleLogin(e) {
this.setState({ showLoader: true });
e.preventDefault();
const request = new Object();
if (this.validator.allValid()) {
request.email = this.state.email;
request.password = this.state.password;
this.props.login(request, () => {
//get callbach here
this.props.history.push('/my-space/my_views');
})
this.setState({ showLoader: false });
} else {
this.setState({ showLoader: false });
this.validator.showMessages();
this.forceUpdate();
}
}
const mapStateToProps = state => {
return {
authState: state
};
};
const mapDispatchToProps = dispatch => {
return {
login: (request, cb) => dispatch(login(request, cb))
};
};
export default connect(mapStateToProps, mapDispatchToProps)(LoginForm);
Hope it helps:)
If you are using redux-thunk, you can return a Promise from your async action.
The function called by the thunk middleware can return a value,
that is passed on as the return value of the dispatch method.
In this case, we return a promise to wait for.
This is not required by thunk middleware, but it is convenient for us.
But I prefer use useEffect or componentDidUpdate for this purpose:
componentDidUpdate(){
if(this.props.authState.isLoggedIn){
this.props.history.push('/my-space/my_views');
}
}
I recommend using the Redux Cool package if you need actions with callback capability.
Instalation
npm install redux-cool
Usage
import {actionsCreator} from "redux-cool"
const my_callback = () => {
console.log("Hello, I am callback!!!")
}
const callbackable_action = actionsCreator.CALLBACKABLE.EXAMPLE(1, 2, 3, my_callback)
console.log(callbackable_action)
// {
// type: "CALLBACKABLE/EXAMPLE",
// args: [1, 2, 3],
// cb: f() my_callback,
// _index: 1
// }
callbackable_action.cb()
// "Hello, I am callback!!!"
When we try to generate an action object, we can pass the callback function as the last argument. actionsCreator will check and if the last argument is a function, it will be considered as a callback function.
See Actions Creator for more details
react-redux/redux dispatch returns a promise. you can do this if you want to return a value or identify if the request is success/error after being dispatched
Action example
export const fetchSomething = () => async (dispatch) => {
try {
const response = await fetchFromApi();
dispatch({
type: ACTION_TYPE,
payload: response.value
});
return Promise.resolve(response.value);
} catch (error) {
return Promise.reject(error);
}
}
Usage
const foo = async data => {
const response = new Promise((resolve, reject) => {
dispatch(fetchSomething())
.then(v => resolve(v))
.catch(err => reject(err))
});
await response
.then((v) => navigateToSomewhere("/", { replace: true }))
.catch(err => console.log(err));
};
this post is old, but hopefully it will help
Package.json
"react-redux": "^8.0.2"
"#reduxjs/toolkit": "^1.8.5"
I am trying to show 4 different array's data. I am calling get service but calling it 4 times. instead i want to make one call. with same link but want to dispatch 4 different actions for different data. as you can see there are 4 const which i want to dispatch and i have to make 4 calls right now. i am using initialload() as to reach to my view in Redux.
export function getcoCodeFilter() {
return new Promise((resolve, reject) => {
fetch(getServiceContext() + 'getfilteroptions', {
method: 'GET',
credentials: 'same-origin'
})
.then((response) => {
if (response.ok) {
response
.json()
.then((json) => {
const filterDisplay = json.data;
const companyList = filterDisplay.companyCodes;
const formtypeList = filterDisplay.formTypes;
const yearList = filterDisplay.yearList;
const qtrList = filterDisplay.quarterList;
resolve(companyList);
});
}
else {
response
.json()
.then((json) => {
const errors = json;
reject(errors ? errors.exceptionMessages : []);
});
}
});
});
}
// get filter formtypes
export function getFormTypesFilter() {
return new Promise((resolve, reject) => {
fetch(getServiceContext() + 'getfilteroptions', {
method: 'GET',
credentials: 'same-origin'
})
.then((response) => {
if (response.ok) {
response
.json()
.then((json) => {
const coTypesList = json.data;
resolve(coTypesList.formTypes);
});
}
else {
response
.json()
.then((json) => {
const errors = json;
reject(errors ? errors.exceptionMessages : []);
});
}
});
});
}
// get year for Filters
export function getYearFilter() {
return new Promise((resolve, reject) => {
fetch(getServiceContext() + 'getfilteroptions', {
method: 'GET',
credentials: 'same-origin'
})
.then((response) => {
if (response.ok) {
response
.json()
.then((json) => {
const coTypesList = json.data;
resolve(coTypesList.yearList);
});
}
else {
response
.json()
.then((json) => {
const errors = json;
reject(errors ? errors.exceptionMessages : []);
});
}
});
});
}
// get quarters
export function getQTRFilter() {
return new Promise((resolve, reject) => {
fetch(getServiceContext() + 'getfilteroptions', {
method: 'GET',
credentials: 'same-origin'
})
.then((response) => {
if (response.ok) {
response
.json()
.then((json) => {
const coTypesList = json.data;
resolve(coTypesList.quarterList);
});
}
else {
response
.json()
.then((json) => {
const errors = json;
reject(errors ? errors.exceptionMessages : []);
});
}
});
});
}
export const getInitialLoad = (dispatch) => {
return new Promise((resolve) => {
getcoCodeFilter().then((companyList) => {
dispatch({
type: 'COCODE_FILTER_DISPLAY',
value: companyList
});
resolve();
});
getFormTypesFilter().then((formtypeList) => {
dispatch({
type: 'FORMTYPES_FILTER_DISPLAY',
value: formtypeList
});
resolve();
});
getYearFilter().then((yearList) => {
dispatch({
type: 'YEAR_FILTER_DISPLAY',
value: yearList
});
resolve();
});
getQTRFilter().then((qtrList) => {
dispatch({
type: 'QTR_FILTER_DISPLAY',
value: qtrList
});
resolve();
});
});
};
What I often do is store all information in an object and dispatch an action with the object. The action will get picked up by one more many reducers.
something similar to this.
export const getInitialLoad = (dispatch) => {
const ResponseData = {}
return new Promise((resolve) => {
getcoCodeFilter().then((companyList) => {
ResponseData["companyList"] = companyList;
resolve();
});
getFormTypesFilter().then((formtypeList) => {
ResponseData["formtypeList"] = formtypeList;
resolve();
});
getYearFilter().then((yearList) => {
ResponseData["yearList"] = yearList;
resolve();
});
getQTRFilter().then((qtrList) => {
ResponseData["qtrList"] = qtrList;
dispatch({
type: 'INITIAL_LOAD_ACTION',
value: ResponseData
});
resolve();
});
});
};
INITIAL_LOAD_ACTION can be called anything and used in any number of reducers. all you have to do is set the sate using something along the lines of
action.payload.value.ResponseData where ResponseData is one of the 4 keys you set above.
EDIT:
export const getInitialLoad = async (dispatch) => {
const ResponseData = {}
ResponseData["companyList"] = await getcoCodeFilter();
ResponseData["formtypeList"] = await getFormTypesFilter();
ResponseData["yearList"] = await getYearFilter();
ResponseData["qtrList"] = await getQTRFilter();
dispatch({
type: 'INITIAL_LOAD_ACTION',
value: ResponseData
});
};
OR you could do something like
export const getInitialLoad = async (dispatch) => {
const ResponseData = await Promise.all([getcoCodeFilter, getFormTypesFilter, getYearFilter, getQTRFilter])
dispatch({
type: 'INITIAL_LOAD_ACTION',
value: ResponseData
});
};
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
I have the following snippet of code
export const fetchPosts = () => async dispatch => {
const res = await axios.get(`${url}/posts`, { headers: { ...headers } });
console.log(res.data);
let posts = res.data.map(p => (p.comments = fetchComments(p.id)));
console.log(posts);
dispatch({ type: FETCH_POSTS, payload: res.data });
};
export const fetchComments = id => async dispatch => {
console.log(id)
const res = await axios.get(`${url}/posts/${id}/comments'`, {
headers: { ...headers }
});
console.log("id", id);
return res.data;
};
when i console log the posts, i get 2 functions returned. what is the proper way in which i should call the fetch comments for this function to return me the desired value?
Add this:
const postsResult = await Promise.all(posts)