Last active
August 7, 2019 14:15
-
-
Save iammerrick/f3f9edfbf5dc279af775f73020193dcc to your computer and use it in GitHub Desktop.
Lazily Load Code Declaratively in React + Webpack
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react'; | |
const toPromise = (load) => (new Promise((resolve) => ( | |
load(resolve) | |
))); | |
class LazilyLoad extends React.Component { | |
constructor() { | |
super(...arguments); | |
this.state = { | |
isLoaded: false, | |
}; | |
} | |
componentWillMount() { | |
this.load(this.props); | |
} | |
componentDidMount() { | |
this._isMounted = true; | |
} | |
componentWillReceiveProps(next) { | |
if (next.modules === this.props.modules) return null; | |
this.load(next); | |
} | |
componentWillUnmount() { | |
this._isMounted = false; | |
} | |
load(props) { | |
this.setState({ | |
isLoaded: false, | |
}); | |
const { modules } = props; | |
const keys = Object.keys(modules); | |
Promise.all(keys.map((key) => toPromise(modules[key]))) | |
.then((values) => (keys.reduce((agg, key, index) => { | |
agg[key] = values[index]; | |
return agg; | |
}, {}))) | |
.then((result) => { | |
if (!this._isMounted) return null; | |
this.setState({ modules: result, isLoaded: true }); | |
}); | |
} | |
render() { | |
if (!this.state.isLoaded) return null; | |
return React.Children.only(this.props.children(this.state.modules)); | |
} | |
} | |
LazilyLoad.propTypes = { | |
children: React.PropTypes.func.isRequired, | |
}; | |
export const LazilyLoadFactory = (Component, modules) => { | |
return (props) => ( | |
<LazilyLoad modules={modules}> | |
{(mods) => <Component {...mods} {...props} />} | |
</LazilyLoad> | |
); | |
}; | |
export const importLazy = (fetch) => (cb) => ( | |
fetch((mod) => cb(mod.default)) | |
); | |
export default LazilyLoad; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<LazilyLoad modules={{ | |
BuzzHandler: importLazy(require('bundle?lazy&name=buzz!./components/BuzzHandler')), | |
BuzzMenuHandler: importLazy(require('bundle?lazy&name=buzz!./BuzzMenuHandler/BuzzMenuHandler')), | |
}}> | |
{({BuzzHandler, BuzzMenuHandler}) => ( | |
<BuzzHandler> | |
<BuzzMenuHandler active={BUZZ_MENU_ITEMS.PINNED}> | |
<BuzzMenu /> | |
</BuzzMenuHandler> | |
</BuzzHandler> | |
)} | |
</LazilyLoad> |
Awesome job.
Niiiiice
I am facing a problem by following this approach. When container component update state and trigger re-render, the child component which is lazily loaded lost its input element focus. E.g. I have a child textbox component and I loaded it lazily in my container component. onChange of textbox component I am updating state of my container component and at that moment the focus is lost from text box. Any help?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Liked the approach, we are also doing something of this kind. But this just gave me idea to organize my code better.