react-react router4 赖加载中,IndexRoute为什么不自动加载Home组件

在 SegmentFault,解决技术问题
每个月,我们帮助 1000 万的开发者解决各种各样的技术问题。并助力他们在技术能力、职业生涯、影响力上获得提升。
一线的工程师、著名开源项目的作者们,都在这里:
获取验证码
已有账号?
标签:至少1个,最多5个
注:本文使用的 react-router 版本为 2.8.1
React Router 是一个非常出色的路由解决方案,同时也非常容易上手。但是当网站规模越来越大的时候,首先出现的问题是 Javascript 文件变得巨大,这导致首页渲染的时间让人难以忍受。实际上程序应当只加载当前渲染页所需的 JavaScript,也就是大家说的“代码分拆" — 将所有的代码分拆成多个小包,在用户浏览过程中按需加载。
官方示例在 。
所得到的效果是:
以前是这样(23333,我真不是故意的。。)
现在是这样:
实际上就是将一个大 javascript 文件拆分成了若干个 chunk file。
下面是改造过程
Webpack 配置
首先在 webpack.config.js 的 output 内加上 chunkFilename
path: path.join(__dirname, '/../dist/assets'),
filename: 'app.js',
publicPath: defaultSettings.publicPath,
// 添加 chunkFilename
chunkFilename: '[name].[chunkhash:5].chunk.js',
name 是在代码里为创建的 chunk 指定的名字,如果代码中没指定则 webpack 默认分配 id 作为 name。
chunkhash 是文件的 hash 码,这里只使用前五位。
以前你的路由大概应该是这样的:(作为需要按需加载的大型应用,路由肯定是相当复杂,这里只列举部分路由举例)
ReactDOM.render(
&Router history={browserHistory}&
{/* 主页 */}
&Route path="/" component={App}&
{/* 默认 */}
&IndexRoute component={HomePage} /&
{/* baidu */}
&Route path="/baidu" component={BaiduPage}&
&Route path="result" component={BaiduResultPage} /&
&Route path="frequency" component={BaiduFrequencyPage} /&
{/* 404 */}
&Route path='/404' component={NotFoundPage} /&
{/* 其他重定向到 404 */}
&Redirect from='*' to='/404' /&
), document.getElementById('app')
按需加载之后,我们需要让路由动态加载组件,需要将 component 换成 getComponent。首先将路由拆出来(因为路由庞大之后全部写在一起会很难看),创建一个根路由 rootRoute:
const rootRoute = {
path: '/',
indexRoute: {
getComponent(nextState, cb) {
require.ensure([], (require) =& {
cb(null, require('components/layer/HomePage'))
}, 'HomePage')
getComponent(nextState, cb) {
require.ensure([], (require) =& {
cb(null, require('components/Main'))
}, 'Main')
childRoutes: [
require('./routes/baidu'),
require('./routes/404'),
require('./routes/redirect')
ReactDOM.render(
history={browserHistory}
routes={rootRoute}
), document.getElementById('app')
history 不变,在 Router 中添加 routes 属性,将创建的路由传递进去。
这里有四个属性:
将匹配的路由,也就是以前的 path。
getComponent
对应于以前的 component 属性,但是这个方法是异步的,也就是当路由匹配时,才会调用这个方法。
这里面有个 require.ensure 方法
require.ensure(dependencies, callback, chunkName)
这是 webpack 提供的方法,这也是按需加载的核心方法。第一个参数是依赖,第二个是回调函数,第三个就是上面提到的 chunkName,用来指定这个 chunk file 的 name。
如果需要返回多个子组件,则使用 getComponents 方法,将多个组件作为一个对象的属性通过 cb 返回出去即可。这个在官方示例也有,但是我们这里并不需要,而且根组件是不能返回多个子组件的,所以使用 getComponent。
indexRoute
用来设置主页,对应于以前的 &IndexRoute&。
注意这里的 indexRoute 写法, 这是个对象,在对象里面使用 getComponent。
childRoutes
这里面放置的就是子路由的配置,对应于以前的子路由们。我们将以前的 /baidu、/404 和 * 都拆了出来,接下来将分别为他们创建路由配置。
上面的childRoutes 里面,我们 require 了三个子路由,在目录下创建 routes 目录,将这三个路由放置进去。
├── 404
└── index.js
├── baidu
├── index.js
└── routes
├── frequency
└── index.js
└── result
└── index.js
└── redirect
└── index.js
和 rootRoute 类似,里面的每个 index.js 都是一个路由对象:
/404/index.js
module.exports = {
path: '404',
getComponent(nextState, cb) {
require.ensure([], (require) =& {
cb(null, require('components/layer/NotFoundPage'))
}, 'NotFoundPage')
/baidu/index.js
module.exports = {
path: 'baidu',
getChildRoutes(partialNextState, cb) {
require.ensure([], (require) =& {
cb(null, [
require('./routes/result'),
require('./routes/frequency')
getComponent(nextState, cb) {
require.ensure([], (require) =& {
cb(null, require('components/layer/BaiduPage'))
}, 'BaiduPage')
/baidu/routes/frequency/index.js
module.exports = {
path: 'frequency',
getComponent(nextState, cb) {
require.ensure([], (require) =& {
cb(null, require('components/layer/BaiduFrequencyPage'))
}, 'BaiduFrequencyPage')
举这几个例子应该就差不多了,其他都是一样的,稍微有点特别的是 redirect。
设置 Redirect
之前我们在根路由下是这么设置重定向的:
&Router history={browserHistory}&
&Route path="/" component={App}&
{/* home */}
&IndexRoute component={HomePage} /&
&Route path="/baidu" component={BaiduPage}&
&Route path="result" component={BaiduResultPage} /&
&Route path="frequency" component={BaiduFrequencyPage} /&
&Route path='/404' component={NotFoundPage} /&
{/* 如果都不匹配,重定向到 404 */}
&Redirect from='*' to='/404' /&
当改写之后,我们需要把这个重定向的路由单独拆出来,也就是
* 这个路由,我们上面已经为他创建了一个 redirect 目录。这里使用到 onEnter 方法,然后在这个方法里改变路由状态,调到另外的路由,实现 redirect :
/redirect/index.js
module.exports = {
path: '*',
onEnter: (_, replaceState) =& replaceState(null, "/404")
The root route must render a single element
跟着官方示例和上面码出来之后,可能页面并没有渲染出来,而是报 The root route must render a single element 这个异常,这是因为 module.exports 和 ES6 里的 export default 有区别。
如果你是使用 es6 的写法,也就是你的组件都是通过 export default 导出的,那么在 getComponent 方法里面需要加入 .default。
getComponent(nextState, cb) {
require.ensure([], (require) =& {
// 在后面加 .default
cb(null, require('components/layer/ReportPage')).default
}, 'ReportPage')
如果你是使用 CommonJS 的写法,也就是通过 module.exports 导出的,那就无须加 .default 了。
24 收藏&&|&&118
你可能感兴趣的文章
117 收藏,1.7k
5 收藏,427
19 收藏,822
本作品采用 署名-非商业性使用-禁止演绎 4.0 国际许可协议 进行许可
非常赞!正需要
非常赞!正需要
entry 怎么设置 难道指向每个component 的 index?
entry 怎么设置 难道指向每个component 的 index?
entry 不用改,还是你的入口文件
entry 不用改,还是你的入口文件
找了一早上,知道自己错在哪里,为什么不能打包出来单独的文件,因为我在另外文件中已经引用了...
找了一早上,知道自己错在哪里,为什么不能打包出来单独的文件,因为我在另外文件中已经引用了...
在另外文件中引用 了是什么意思阿?什么引用 了会打包不出来单独的文件。。。
在另外文件中引用 了是什么意思阿?什么引用 了会打包不出来单独的文件。。。
大神 您好 刚好读了一篇您写的文章 正好我在使用react-router遇到了一些问题,想请问您一下,我在使用动态路由配置的时候访问子路由 比如
根路由(上应该还有个导航栏的组件
就不显示出来了 请问您了解这个情况么
还是说每个路由匹配的路径都是一定要是一个完整的页面
子路由引入的组件不会加在原有的跟路由上面么
大神 您好 刚好读了一篇您写的文章 正好我在使用react-router遇到了一些问题,想请问您一下,我在使用动态路由配置的时候访问子路由 比如http://localhost:8000/market
根路由(http://localhost:8000/)上应该还有个导航栏的组件
就不显示出来了 请问您了解这个情况么
还是说每个路由匹配的路径都是一定要是一个完整的页面
子路由引入的组件不会加在原有的跟路由上面么
希望我的语言表述的够明白
希望我的语言表述的够明白
你好,根据你的描述你的根路由应该是匹配的是一个主组件,比如App,然后在App里面引用导航栏组件以及 this.props.children,路由也是一样的,在根路由 / 里面配 /market 路由。导航栏不见了是否是因为你的根路由和market路由是平级的而不是父子关系?
你好,根据你的描述你的根路由应该是匹配的是一个主组件,比如App,然后在App里面引用导航栏组件以及 this.props.children,路由也是一样的,在根路由 / 里面配 /market 路由。导航栏不见了是否是因为你的根路由和market路由是平级的而不是父子关系?
主入口文件
const store = configureStore();// 定义根路由const rootRoute = {
childRoutes: [ {
path: '/',
component: require('components/Main').default,
childRoutes: [
require('./components/market/route')
// Render the main component into the dom
&Provider store = {store}&
&Router history={browserHistory} routes={rootRoute}/&
&/Provider&),document.getElementById('app')
主组件class AppComponent ponent {
render() {
&FrameHeader /&
{this.props.children || &FrameContentWrap /&}
AppComponent.defaultProps = {
export default AppC
子路由module.exports = {
path: 'market',
getComponent(nextState, cb) {
require.ensure([], (require) =& {
require('components/market/MarketWrap').default)
}, 'market')
childRoutes: [
require('components/market/index/route'),
require('components/market/stock/route')
入口文件 在 主组件的外层
子路由的外层
怎么判断是不是平级关系呢
主入口文件
const store = configureStore();
// 定义根路由
const rootRoute = {
childRoutes: [ {
path: '/',
component: require('components/Main').default,
childRoutes: [
require('./components/market/route')
// Render the main component into the dom
&Provider store = {store}&
&Router history={browserHistory} routes={rootRoute}/&
&/Provider&),document.getElementById('app')
class AppComponent ponent {
render() {
&FrameHeader /&
{this.props.children || &FrameContentWrap /&}
AppComponent.defaultProps = {
export default AppC
module.exports = {
path: 'market',
getComponent(nextState, cb) {
require.ensure([], (require) =& {
require('components/market/MarketWrap').default)
}, 'market')
childRoutes: [
require('components/market/index/route'),
require('components/market/stock/route')
入口文件 在 主组件的外层
子路由的外层
怎么判断是不是平级关系呢
你的问题是首页可以打开,然后从首页进market之后首页上的导航不见了,但是market组件正常显示是吗?
你的问题是首页可以打开,然后从首页进market之后首页上的导航不见了,但是market组件正常显示是吗?
访问 导航不见了,但是market组件正常显示
访问http://localhost:8000/
访问http://localhost:8000/market 导航不见了,但是market组件正常显示
代码方便放到github上么
在这里不太好看
代码方便放到github上么
在这里不太好看
/duanjianan/market.git
大神 方便的话可以加一下联系方式么
大神 方便的话可以加一下联系方式么
抱歉 昨天一直在忙
今天才看见 已经给你发了好友申请了
抱歉 昨天一直在忙
今天才看见 已经给你发了好友申请了
楼主也加我下,我也有问题想请教,q
楼主也加我下,我也有问题想请教,q
我按照你的方法写了,但是页面初始化还是只加载了一个js啊,也没报错,就是index.html应该怎么引入啊,或者webpack.config.js要怎么配置啊??能不能加下QQ: 三克油
我按照你的方法写了,但是页面初始化还是只加载了一个js啊,也没报错,就是index.html应该怎么引入啊,或者webpack.config.js要怎么配置啊??能不能加下QQ: 三克油
我的哥,rootRoute 中的Main是哪里来的,未按需加载的时候这个Main用在哪里了?
我的哥,rootRoute 中的Main是哪里来的,未按需加载的时候这个Main用在哪里了?
分享到微博?
我要该,理由是:webpack和React Router按需加载在 SegmentFault,解决技术问题
每个月,我们帮助 1000 万的开发者解决各种各样的技术问题。并助力他们在技术能力、职业生涯、影响力上获得提升。
一线的工程师、著名开源项目的作者们,都在这里:
获取验证码
已有账号?
问题对人有帮助,内容完整,我也想知道答案
问题没有实际价值,缺少关键内容,没有改进余地
有定义的Router如下所示:
const routes = (
&Router history={history}&
&Route path="/" component={AppRoot}&
&IndexRoute component={Home} /&
&Route path="signup" component={Signup} /&
&Route path="login" component={Login} /&
&Route path="logout" component={Logout} /&
&Route path="*" component={NotFound} /&
浏览器访问http://localhost:3000/时,没有自动加载Home组件,鼠标点击一下页面上的首页,就可以加载,是怎么回事?如何访问http://localhost:3000/时自动加载IndexRoute的Home组件?
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
请问下解决方案是什么?
该答案已被忽略,原因:
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
找到问题了!
分享到微博?
关闭理由:
删除理由:
忽略理由:
推广(招聘、广告、SEO 等)方面的内容
与已有问题重复(请编辑该提问指向已有相同问题)
答非所问,不符合答题要求
宜作评论而非答案
带有人身攻击、辱骂、仇恨等违反条款的内容
无法获得确切结果的问题
非开发直接相关的问题
非技术提问的讨论型问题
其他原因(请补充说明)
我要该,理由是:}

我要回帖

更多关于 react router重新加载 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信