Skip to content

Instantly share code, notes, and snippets.

@iammerrick
Last active August 7, 2019 14:15
Show Gist options
  • Star 36 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save iammerrick/f3f9edfbf5dc279af775f73020193dcc to your computer and use it in GitHub Desktop.
Save iammerrick/f3f9edfbf5dc279af775f73020193dcc to your computer and use it in GitHub Desktop.
Lazily Load Code Declaratively in React + Webpack
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;
<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>
@sujoy18
Copy link

sujoy18 commented Jul 13, 2017

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