react-async-state v0.0.3
React Async State
React higher order componet that helps you to work with async data
npm install --save --save-exact react-async-state
Motivation
How many times did you struggle with this error?
> Uncaught Error: Invariant Violation: replaceState(...): Can only update a mounted or mounting component.
Yes React.createClass
allowed you to check this.isMounted()
but new fancy es6
classes dropped this functionality and it's become an antipattern.
So everything you can do is to use (or make your own) cancelable promises or implement your own isMounted
functionality.
But hey!
You got flux
/redux
/anyux
tools that will control your async data flow and everything you need is to subscribe and unsubscribe to it's stores.
So why you need this tool ?
In most cases you don't.
Still why ?
Let's assume you got simplest component - FacebookLoginButton
and everything you want it to do is to pass to it's parent accessToken
if user will click on it and go through authorization steps.
And the most important is that this component can be mounted and unmounted at any time.
And you really really really don't want to create store for it.
Easy peasy:
export default class FacebookLoginButton extends Component {
componentDidMount() {
loadFB().then(FB => {
this.setState({FB});
});
}
render() {
return (
<button onClick={() => this.state.FB.login()}>
Sign in with Facebook
</button>
);
}
}
Does it look wrong?
- First - you should disable click when
FB
isundefined
. - Second - cancel the promise.
export default class FacebookLoginButton extends Component {
componentDidMount() {
loadFB().then(FB => {
if (!this._cancelPromise) {
this.setState({FB});
}
});
}
componentWillUnmount() {
this._cancelPromise = true;
}
render() {
return (
<button
disabled={!this.state.FB}
onClick={() => this.state.FB.login()}>
Sign in with Facebook
</button>
);
}
}
Done what next?
You will need to implement GoogleLoginButton
, TwitterLoginButton
, AnyOtherSocialLoginButton
.
Use react-async-state
!
import {
AsyncState
} from 'react-async-state';
const decorator = AsyncState(() => loadFB().then(FB => ({FB})));
class FacebookLoginButton extends Component {
render() {
return (
<button
disabled={!this.props.FB}
onClick={() => this.props.FB.login()}>
Sign in with Facebook
</button>
);
}
}
export default decorator(FacebookLoginButton);
Or if you like es7 syntax
import {
AsyncState
} from 'react-async-state';
@AsyncState(async () => ({
FB: await loadFB()
}))
export default class FacebookLoginButton extends Component {
render() {
return (
<button
disabled={!this.props.FB}
onClick={() => this.props.FB.login()}>
Sign in with Facebook
</button>
);
}
}
Examples
License
MIT