I have this pattern all over my codebase:
const ComponentA = React.createClass({
propTypes: {
id: PropTypes.string,
},
contextTypes,
getInitialState() {
return {};
},
componentDidMount() {
http.get(this.context.rootUrl + "SomeAPI", {id: this.props.id})
.then(config => {
if (this.isMounted())
this.setState({data});
});
},
render() {
return this.state.data
? (<ComponentB {...this.props} {...this.state.data}/>)
: (<Spinner/>);
}
});
A component, such as ComponentA, has to make an ajax call on mount, and then pass that data to another component on completion. I'm imagining a HOC signature that looks something like this:
onMount(
getData: (props: Object, context: Object) => Promise,
BaseComponent: ReactElementType
): ReactElementType
Thanks for the suggestion! I'm not sure to what extent Recompose should be providing lifecycle hooks. I'd like to think about this for a while before making any decisions.
Hmmm. Well, one option would be to have a separate package recompose-lifecycle for stuff like that, if there's enough code to justify one. Anyways, here's my naive implementation of onMount:
const onMount = (getData, BaseComponent) => React.createClass({
contextTypes: BaseComponent.contextTypes,
getInitialState() {
return {};
},
componentDidMount() {
getData(this.props, this.context)
.then(promise => {
if (this.isMounted)
this.setState({promise});
});
},
render() {
return (
<BaseComponent {...this.props} {...this.state.promise} />
);
},
});
Lifecycle events are cool but I think there is no reason for packages like recompose-lifecycle in that case. Quick example:
import React from 'react'
import { render } from 'react-dom'
import { compose, lifecycle, branch, renderNothing, withState, renderComponent } from 'recompose'
// returns HOC
const componentWithApi = (BaseComponent, requests) => (
compose(
// are we done?
withState('loaded', 'setLoaded', false),
lifecycle(
(c) => (
// Lets make all requests and then update state
Promise.all(requests.map(r => r()))
.then(() => c.props.setLoaded(true))
),
() => {}
),
// You can show some loader while data are loading or
// render nothig.
branch(
({ loaded }) => loaded,
// BOOOM! Ready to go!
renderComponent(BaseComponent),
// loading ... loading .. loading
renderComponent(() => <div>loader</div>),
)
)(renderNothing())
)
// Your complex application
const App = ({ loaded }) => <div>App { loaded ? 'yes' : 'no' }</div>
App.propTypes = { loaded: React.PropTypes.bool }
// Array of requests (set timeout mock)
const requests = [
() => new Promise((resolve) => setTimeout(resolve, 1000)),
() => new Promise((resolve) => setTimeout(resolve, 2000))
]
// You can wrap any component with componentWithApi function
const AppWithApi = componentWithApi(App, requests)
render(<AppWithApi />, document.querySelector('#app'))
@RafalFilipek This breaks in universal app situations (server-side kick-off alongside client-side run-time).
The missing aspect here is that a lifecycle method such as componentDidMount is essential to some (many) data loading scenarios in universal apps, because it is invoked on client but not on server. As long as recompose doesn't offer some way of making this distinction, it won't enable me to get rid of the class notation.
Btw, I'm currently using the following home-grown doOnMount function:
import { Component } from 'react';
import createHelper from 'recompose/createHelper';
import createElement from 'recompose/createElement';
export const doOnMount = createHelper(callback => BaseComponent =>
class extends Component {
componentDidMount() {
callback(this.props);
}
render() {
return createElement(BaseComponent, this.props);
}
}
, 'doOnMount');
Let's find out how it suits my purpose…
I am agree with @timmolendijk. componentDidMount is pretty useful and it's the reason why react-lifecycle-hoc exists. Currently, the only implementation in react-lifecycle-hoc is componentDidMount.
However, it seems like there is still no consensus whether recompose should provide lifecycle hooks. See #124.
Closing because we now have two ways to do this: rx-recompose's mapPropsStream (which will soon be part of Recompose itself) and the lifecycle helper. Any other proposals should be brought up in a separate issue/PR. Thanks!
Most helpful comment
Lifecycle events are cool but I think there is no reason for packages like
recompose-lifecyclein that case. Quick example: