React性能优化之组件动态加载(react-loadable)
React 项⽬打包时,如果不进⾏异步组件的处理,那么所有页⾯所需要的 js 都在同⼀⽂件中(bundle.js),整个js⽂件很⼤,从⽽导致⾸屏加载时间过长。
所有,可以对组件进⾏异步加载处理,通常可以使⽤React-loadable。
React-loadable 使⽤
例如,对于项⽬中的detail组件(/src/pages/detail/),在 detail ⽬录下新建 loadable.js:
import React from 'react';
import Loadable from 'react-loadable';
const LoadableComponent = Loadable({
loader: () => import('./index.js'),
loading() {
return <div>正在加载</div>
},
});
export default () => <LoadableComponent/>
然后在 app.js ⾥⾯引⼊detail组件:
// 不适⽤ react-loadable 时的引⼊⽅式:
// import Detail from './pages/detail/index';
// 使⽤ react-loadable 时的引⼊⽅式:
import Detail from './pages/detail/loadable';
... ...
class App extends Component {
render() {
return (
<Provider store={store}>
<Fragment>
<BrowserRouter>
··· ···
<Route path='/detail/:id' exact component={Detail}></Route>
··· ···
</BrowserRouter>
</Fragment>
</Provider>
)
}
}
但是,在/pages/detail/index.js⽂件中,如果想访问到当前路由的 match,location,history对象,就访问不到了
需要使⽤withRouter对 /detail/index.js 作如下处理:
import { withRouter } from 'react-router-dom';
class Detail extends Component {
render() {
··· ···
}
componentDidMount() {
// withRouter处理后,就可以在这⾥拿到 match 对象了
console.log(this.props.match);
Detail(this.props.match.params.id);
}
}
··· ···
export default connect(mapStateToProps, mapDispatchToProps)(withRouter(Detail));
withRouter 可以将⼀个⾮路由组件包裹为路由组件,使这个⾮路由组件也能访问到当前路由的match, location, history对象。
统⼀处理
上⾯已经实现了动态加载 detail 组件的⽅式,但是如果有多个组件时,需要在每个组件下新建 loadable.js ,⽐较⿇烦,所有可以统⼀封装处理所有组件的动态加载。
新建⽬录/src/utils,新建⽂件 /src/utils/loadable.js
import React from 'react';
import Loadable from 'react-loadable';
export default (loader) => {
react router dom 6
return Loadable({
loader,
loading() {
return <div>正在加载</div>
},
});
}
在 app.js 中,
import loadable from './utils/loadable';
import Header from './common/header';
<!--异步加载组件-->
const Home = loadable(() => import('./pages/home'));
const Detail = loadable(() => import('./pages/detail'));
const Login = loadable(() => import('./pages/login'));
const Write = loadable(() => import('./pages/write'));
class App extends Component {
render() {
return (
<Provider store={store}>
<Fragment>
<BrowserRouter>
<div>
<Header />
<Switch>
<Route
exact
path="/"
render={() => <Redirect to="/home" />}
/>
<Route path='/home' exact component={Home}></Route>
<Route path='/login' exact component={Login}></Route>
<Route path='/write' exact component={Write}></Route>
<Route path='/detail/:id' exact component={Detail}></Route>
<Route render={() => <div>Not Found</div>} />
</Switch>
</div>
</BrowserRouter>
</Fragment>
</Provider>
)
}
}
export default App;