Reputation: 282915
I'm talking about the mapStateToProps
argument of connect
.
One of my components has a property called rules
which is an array of functions. In mapStateToProps
I invoke those rules, passing in the current state. The rules either return an error message or true
if there is no error. I put these error messages into a new prop so that the final component receives an array of error messages instead of an array of functions.
So far this has been working great, but now I want to add support for asynchronous rules. My plan right now is that whenever a rule returns a Promise instead of an error string, I will push a message like "Checking..." into the array of error messages instead, but once the promise is settled I need to "refresh" this array and insert the resolved message.
I figure if I can force an update then redux will have to call mapStateToProps
again. In such a case, all the rules would be re-evaluated, but if I'm not careful I would receive a new Promise which would put right back to square one. However, if I memoize these rules then I can get back the same Promise instance as before, and then check if it's settled and then put that value into my error array instead.
So now the only problem is figuring out how to get a reference to the component instance within the context of mapStateToProps
which only has access to the current state and props.
Is there any way I can force a re-render once my Promise has resolved?
Alternatively, if I could dispatch
an action when it's resolved, I could work with that as well.
Upvotes: 3
Views: 2019
Reputation: 4219
How about creating a stateful component? If you keep the results from your promises in the component's state, it will automatically re-render the component once the promises resolve.
import React, {Component} from 'react';
import {connect} from 'react-redux;
import Promise from 'promise';
class MyStatefulComponent extends Component {
constructor(props) {
this.state = {
messages: [] // initialize empty, or with the synchronous rules
};
}
componentWillMount() {
const setState = this.setState;
const rules = this.props.rules; // rules contains a list of either evaluated rules or promises
Promise.all(rules).then(results => {
// this is executed once all the promises in rules have resolved
// setState will trigger a re-render of this component
setState({
messages: [] // construct your array of messages here from the results
});
})
}
render() {
// render your list of messages
return <ul>
{this.state.messages.map(message => <li>{message}</li>)}
</ul>;
}
}
export default connect(
(state, ownProps) => ({
rules: ownProps.rules.map(rule => rule(state))
})
)(MyStatefulComponent);
Upvotes: 1
Reputation: 67489
You can't do that in mapState
. The mapState
function is intended to be totally synchronous. If you need to do something async, trigger that outside of mapState
, store some values in state, and update them with the results to force mapState
to re-run.
Upvotes: 2