Implementing Lazy Loading in React: Techniques, Components, and Higher‑Order Functions
This article explains why lazy loading is needed for React front‑end projects, demonstrates several code‑first implementations—including a custom LazyComponent, prop‑forwarding tricks, and a higher‑order lazy() function—showing how to improve first‑screen rendering while handling state updates correctly.
When Facebook open‑sourced React at JSConf 2013, its declarative, component‑based approach quickly became popular, but loading many modules on the first screen can hurt render performance and user experience.
To address this, the article explores lazy (asynchronous) loading: initially show a placeholder or nothing, load the module in the background, then re‑render the real component once it is ready.
Example
class Hello extends Component {
constructor(props){
super(props)
this.state = {}
}
render() {
return (
<div className="container">
<div>{this.props.title}</div>
</div>
);
}
}is used to illustrate a simple component that will be lazily loaded.
A first lazy implementation,
class FakeHello extends Component {
constructor(props){
super(props)
this.state = { moduleLoaded:false }
this._module = null
}
componentDidMount(){
if(!this.state.moduleLoaded){
setTimeout(() => {
this._module = require('../hello').default
this.setState({moduleLoaded:true})
},1000)
}
}
render(){
if(!this.state.moduleLoaded){
return <div>loading</div>
} else {
let M = this._module
return <M {...this.props} />
}
}
}shows a loading placeholder and swaps in the real component after a delay, with a button toggling visibility.
To make lazy loading reusable, a generic
class LazyComponent extends Component {
constructor(props){
super(props)
this.state = { show:!!_module }
}
componentDidMount(){
setTimeout(() => {
_module = this.props.render()
this.setState({show:true})
}, this.props.time)
}
render(){
if(!this.state.show){
return this.props.default || <div>will appear later</div>
}
return _module
}
}is introduced, with time controlling when loading starts and render supplying the module.
When the parent’s state changes (e.g., a new title), the wrapped component does not update because the lazy wrapper does not receive the changed props. The fix is to pass all dependent data through the wrapper, for example using a realProps object or a load function that returns the component.
Finally, a higher‑order function
function lazy(loadFun, defaultRender = () => <div>loading</div>, time = 17){
let _module
return class extends Component {
constructor(props){
super(props)
this.state = { show:!!_module }
}
componentDidMount(){
if(!_module){
setTimeout(() => {
_module = loadFun()
this.setState({show:true})
}, time)
}
}
render(){
return this.state.show ? <_module {...this.props} /> : defaultRender()
}
}
}wraps any component, allowing usage like
const LazyHello = lazy(() => require('./components/hello').default, () => <Loading />, 1000);
<LazyHello title="I'm the content"/>.
In summary, two practical lazy‑loading solutions are presented: a dedicated LazyComponent with explicit load and default props, and a reusable higher‑order lazy function that turns ordinary components into lazily loaded ones.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Ctrip Technology
Official Ctrip Technology account, sharing and discussing growth.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
