react中路由和按需加载问题
1 基本的路由设置
react-router可以解决路由问题,只需要添加[基于react-router4.x
]
yarn add react-router-dom
然后在index.js
中引入它,使用:
import {Link,BrowserRouter,Switch, Route} from 'react-router-dom';
ReactDOM.render((
<BrowserRouter>
<Switch>
<Route path="/list" component={ListDemo}/>
<Route path="/a" component={A}/>
<Route path="/b" component={B}/>
</Switch>
</BrowserRouter>
),mountdom)
这样就完成了路由的设置,而超链接则可以使用提供的Link
组件
<Link to="/a">a</Link>
等价于直接写<a href="/a">a</a>
。
2 如何完成路由的菜单部分
在每个menu中传一个url属性,然后url代表那个地方被高亮,每个路由都重新创建一个menu即如下:
<BrowserRouter>
<Switch>
<Route exact path="/" render={props=><Menu {...props} url="list"><ListDemo/></SiderDemo>}/>
<Route path="/list" render={props=><Menu {...props} url="list"><ListDemo/></SiderDemo>}/>
<Route path="/a" render={props=><Menu {...props} url="a"><A/></SiderDemo>}/>
<Route path="/b" render={props=><Menu {...props} url="b"><B/></SiderDemo>}/>
</Switch>
</BrowserRouter>
但是每个页面的初次加载都会闪一下,重新加载了js。要想不闪则需要路由嵌套:
//上来路由只匹配到Menu中
<BrowserRouter>
<Switch>
<Route path="/" component={Menu}/>
</Switch>
</BrowserRouter>
//上面的route就一个组件menu,在menu中再次定义route,可以实现路由嵌套
<Menu>
<顶部></顶部>
<侧栏 selectedurl={this.props.location.pathname}>
</侧栏>
<内容部分>
<Route exact path="/list" component={List}/>
<Route exact path="/a" component={At}/>
<Route exact path="/b" component={Bt}/>
</内容部分>
<Menu>
这里主要是利用了每个页面都有的一个属性即props.location.pathname
是路由属性
3 如何将每个路由的js文件分开输出
1 多入口文件的形式,但是不易于按需加载,只能是实现了分开输出,没啥用。一般写的都是单入口应用。
2 异步import,或者require.ensure,然后在webpack中配置
output:{
filename:"[name]-bundle.js",
chunkFilename: "[name]-chunk.js",
path: __dirname+'/dist'
},
这样就生成一个bundle文件,多个chunk文件,name就是import的文件的名字,注意这里的注释是有用的直接决定了chunk输出的时候的[name]。
import(/* webpackChunkName: "app" */'./app').then(function(res){
let xx= res.default;//xx就是app的export default
})
4 react-router按需加载配置
create-react-app
创建的应用执行npm run eject
进行弹射。webpack中已经有了上面3中的配置,是可以直接生成多个chunk文件的。- 创建一个函数用于生成异步组件:
import React, { Component } from "react";
export default function asyncComponent(importComponent) {
class AsyncComponent extends Component {
constructor(props) {
super(props);
this.state = {
component: null
};
}
async componentDidMount() {
const { default: component } = await importComponent();
this.setState({
component: component
});
}
render() {
const C = this.state.component;
return C ? <C {...this.props} /> : null;
}
}
return AsyncComponent;
}
- 改变组件引入方式之前是直接import现在改为
const List=asyncComponent(()=>import(/* webpackChunkName: "list" */"./router/List"))
const At=asyncComponent(()=>import(/* webpackChunkName: "a" */"./router/A"))
const Bt=asyncComponent(()=>import(/* webpackChunkName: "b" */"./router/B"))
- 渲染
<HashRouter>
<Switch>
<Route path="/" component={SiderDemo}/>
</Switch>
</HashRouter>
class SiderDemo extends React.Component {
render() {
let selected=this.props.location.pathname.substring(1)
if(selected==="")selected="list"
return (
<Layout>
<Sider>
<Menu defaultSelectedKeys={[selected]}>
.........................
</Menu>
</Sider>
<Layout>
<Header></Header>
<Content >
<div>
<Route exact path="/list" component={List}/>
<Route exact path="/a" component={At}/>
<Route exact path="/b" component={Bt}/>
<Route exact path="/" component={List}/>
</div>
</Content>
<Footer></Footer>
</Layout>
</Layout>
);
}
}