I'm pretty new in React-Redux. Was working on an application. The thing is that I faced some issues with asynchronous execution of Redux actionCreator, may be.
Below is my component. Say, I want to call an actionCreator from componentDidMount()
or from an onclick event listener.
class Dashboard extends PureComponent {
componentDidMount() {
this.props.getProductsAndPackages();
let something = [];
something = this.props.products;
}
....................................
}
Or , the function this.props.getProductsAndPackages();
can be an onClick event handler that does the same thing, context is the same. I'll ask my question after first explaining my code.
At the lower side of my Dashboard container:
Dashboard.propTypes = {
getProductsAndPackages: PropTypes.func.isRequired,
products: PropTypes.array.isRequired,
.......................
};
const mapStateToProps = (state) => {
return {
.....................
products: state.products.products,
...................
};
};
const mapDispatchToProps = (dispatch) => {
return {
getProductsAndPackages: () => dispatch(getProductsAndPackagesActionCreator()),
};
};
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Dashboard));
My actionCreator goes like:
export const getProductsAndPackagesActionCreator = () => {
return (dispatch) => {
dispatch(productsIsLoading(true));
let url = 'xyz';
if(!!localStorage.getItem('_token')) {
const local_token = localStorage.getItem('_token');
const fullToken = 'Bearer '.concat(local_token);
axios.get(url, {headers: {Authorization: fullToken}})
.then(response => {
dispatch(productsIsLoading(false));
if (response.data.statusCode === 200) {
dispatch(productsFetched(true));
dispatch(products(response.data.data));
} else {
dispatch(productsFetched(false));
dispatch(productsErrors(response.data.message));
}
})
.catch(error => {
});
} else {
axios.get(url)
.then(response => {
dispatch(productsIsLoading(false));
if (response.data.statusCode === 200) {
dispatch(productsFetched(true));
dispatch(products(response.data.data));
} else {
dispatch(productsFetched(false));
dispatch(productsErrors(response.data.message));
}
})
.catch(error => {
console.log(error);
dispatch(productsIsLoading(false));
dispatch(productsErrors(error.message));
});
}
};
};
Now, I want my getProductsAndPackagesActionCreator()
to return a Promise or anything that would allow my something
variable to get the actual data returned from the server. Right now, by the time I'm getting actual data, the line something=this.props.products
has already been executed and I get back the initialValue that was set for products
.
I know, whenever I'll receive the populated products
, component will re-render, but that does not help my decision making.
I'm using redux-thunk
, by the way.
What should I do now ? Sorry for such a long post.
By default, Redux's actions are dispatched synchronously, which is a problem for any non-trivial app that needs to communicate with an external API or perform side effects. Redux also allows for middleware that sits between an action being dispatched and the action reaching the reducers.
An action creator is a function that literally creates an action object. In Redux, action creators simply return an action object and pass the argument value if necessary.
Thunk functions can be used for both asynchronous and synchronous logic.
Actually I wanted getProductsAndPackagesActionCreator()
to return a promise, which was pretty straightforward, to be honest. I figured out that if you just return
the axios.get()
or axios.post()
, it will return a promise. So, the modified code looked like below:
export const getProductsAndPackagesActionCreator = () => {
return (dispatch) => {
dispatch(productsIsLoading(true));
let url = 'xyz';
if(!!localStorage.getItem('_token')) {
return axios.get(url, {headers: {Authorization: fullToken}})
.then(response => {
............
............
})
.catch(error => {
});
} else {
return axios.get(url)
.then(response => {
...........
...........
})
.catch(error => {
console.log(error);
});
}
};
};
And then, I could do something like below in componentDidMount()
or on any onClick event:
this.props.getProductsAndPackages().then(() => {
this.setState({
...this.state,
clicked_product: this.props.product_by_id
}, () => {
//do other stuffs
});
});
Feel free to let me know if there's any issue.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With