React 性能优化之组件动态加载(react-loadable)
emer 发布于 2021-11-15 09:25 1399 次阅读
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); this.props.getDetail(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) => { 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;