这个问题很怪,我两个二级路由从链接进入的时候,会挂载两次子组件。

  • 从链接进入,是因为新页面在新标签页打开的。

  • 有子组件是因为公共组件提取

  • 同样的操作,有一些简单的二级路由页面,就不会挂载两次。

讲道理,没有理由有的可以,有的不可以,程序是死的,所以我断定出现这种差异,是因为代码有bug了。那么问题来了,怎么定位这个问题?

关于定位这个问题,这次吃了个大亏,说一下思路和过程吧。

  1. 第一症状是这样的,链接进入二级路由,会发出两个相同的网络请求,这个请求是放在 componentDidMount 生命周期里的,如你所知,这个生命周期是用来做初始化操作的。

    在组件的生命周期里 只会被调用一次。那么,两次请求的意思很明显,挂载了两次,到这里是很自然而然的考虑。so,在 componentWillUnmount生命周期里alert进行验证,猜想是需要验证才能确定的

  2. 确定了两次挂载后,就要考虑,哪些因素会让这个组件销毁一次?(找到销毁的原因等同于找到了挂两次的原因)

  • 【三元判断】 在react世界里,没有类似vue中 keep-alive这种保存组件状态的东西, 我管它叫做 离开即销毁。在开发中会经常用三元运算,来做显示不显示(这里没有隐藏,只有销毁)。

    so,我首先想到的也是这个可能,(至少检查过之后,可以排除这个问题)。我进行了长时间的检查(从二级路由的路由组件,到父组件,到layout布局组件,甚至祖先级的兄弟组件 都进行了检查,这个工作量有点大了,这是需要注意的地方,以后在排查问题的过程中,应该首先保证有限的因素先排查,最后才大海捞针,节省时间),结果跟你想的一样,毫无所获。那么这个三元判断的因素先排除。

  • 【路由跳转?配置?】排除了上一个,再要想到的就是路由跳转和配置方面的问题。这里的路由还是老式的 对象配置方法(对象平铺,并不能嵌套),所以把路由捋了一遍,也没有发现什么问题。那么考虑会不会是配置出了问题呢?于是我又配置了一个测试路由,,配置顺序?匹配顺序?发现也有同样的问题,搞的我一下子不知所措了。彻底懵了。再仔细想想,还有什么能影响这个呢?我想了很久,还是没有头绪。难顶。。。

  • 【安装devtools开发工具调试】 平常开发过程中,我一般是不用这个工具的,用不着,今天装上用它调试了一下,检查里 也没有发现什么问题,请求两次 ,state和props也没有异常。

  • 【点开主页,开始思考路由的嵌套】 没有头绪,还是没有头绪,然后我刷新了一会主页,发现主页始终是正常的,这一方面说明路由还是在正常工作的,另一方面,也说明我的代码结构里 还是有问题的。所以,遇到问题的时候,不能放弃,不要放弃。 我查了一些资料,没有相似的问题,我还傻兮兮的照着别人的博客多写了一个重定向,希望把父组件先加载进来,结果也是没什么用。我甚至考虑用render,children来重写这块的路由规则。

 <Switch>
{getRoutes(match.path, getRouters(routerData,match)).map(item => (
<Route
key={item.key}
path={item.path}
component={item.component}
exact={item.exact}
/>
))}
<Redirect to='/user/index/ioc' />
</Switch>

在思考路由的过程中,我还对每一级的路由进行了过滤,

	const { routerData, match } = this.props;
const getRouters = (routerData,match) =>{
const routes = {}
Object.keys(routerData).map(route => {
if(route.indexOf(match.path)>-1){
return routes[route] = routerData[route];
}
})
return routes
}

在这个过程中,也感受到这种平铺对象操作的繁琐。但是到目前为止,关于这个bug的原因,没有一点进展,没有定位到问题所在,也没有解决方案。

  • 【柳暗花明】事情的转机出现在我6点下楼抽了一颗烟,空气中分不清是雾还是霾,我觉得 实在找不到原因,就重写一下页面,或者对项目进行一个大重构。回来之后,我把这个组件挂到主页路由上,这时候奇迹出现了,不会挂载2次了,我那个兴奋啊 , 从业以来花时间最长的bug,终于可以让我喘口气,我把这个页面放在一级路由,发现是完美运行的。 到这里,业务上的问题可以解决,但是还是没有把问题搞清楚。

    于是,我考虑二级路由的问题,我至今还是没想明白为什么二级路由,别的页面不会挂载2次,仅这两个页面挂载2次,隐约觉得,这两个页面也是有问题的。

  • 【其他尝试】发现二级路由的问题之后,由于并不想把它俩放在顶层路由,我干脆给它放到三级路由了,原始页面仍然有问题,换空白组件测试,通过了。然后一下一下的还原,发现只要引入了一个table的公共组件,就会挂载2次。

  • 【最后】最后又尝试二级路由,不显示table组件,这种情况下,发现也是正常的,所以基本排除路由的问题了。

解决方案:

  1. 提升至顶级路由。(利:快速解决问题 弊: 并没有从根源上解决 而且挂在顶级路由下 并不是个好的做法)
  2. 改造table公用组件。

问题到这里算是基本找到原因了,但具体是为什么会出现这种情况,明天再尝试解决,先把过程记录下来。在react世界里,到处都充满了蝴蝶效应,有时候你的一个巨大bug,很可能就是一个逗号引起的,所以搞react开发的同学,要更认真仔细了

问题算是解决了,最后定位到问题,是由于 react-csv-downloader这个插件引起的,只要引入这个插件就会有这个问题。换了一个react-csv果然没有这个问题了,也跟路由没关系了。

链接进入react二级路由,引发的子组件二次挂载的更多相关文章

  1. vue-router 使用二级路由去实现子组件的显示和隐藏

    在需求中有一个这样的情况:一个组件在主组件和另外的组件中引用,且点击主组件和这个组件分别有相应得切换事件. 一开始的时候我是没有划分组件,把它们放到主组件内,这样便于切换,但是主主件内有独立的部分需要 ...

  2. React 克隆组件 -- React.cloneElement(可以用来修改子组件属性值,复制子组件,添加子组件)

    项目要求实现按钮级权限,简单来说就是需要通过后台数据绑定来控制前端页面哪些操作按钮需要渲染,哪些操作按钮不需要渲染, 大体的方案是: 在原有的按钮标签外再套一层按钮权限控制标签,然后每个具体的按钮对照 ...

  3. 九、React中的组件、父子组件、React props父组件给子组件传值、子组件给父组件传值、父组件中通过refs获取子组件属性和方法

    一.概述 React中的组件: 解决html 标签构建应用的不足. 使用组件的好处:把公共的功能单独抽离成一个文件作为一个组件,哪里里使用哪里引入. [父子组件]:组件的相互调用中,我们把调用者称为父 ...

  4. React 函数式组件的 Ref 和子组件访问(useImperativeHandle)

    引入:如何调用函数式组件内部的方法 对于 React 中需要强制修改子组件的情况,React 提供了 Refs 这种解决办法,使得我们可以操作底层 DOM 元素或者自定的 class 组件实例.除此之 ...

  5. React对比Vue(04 父子组件的通信 )

    跟vue差不多 都是props,但是react里面不仅可以给子组件传值,还可以传方法,MD尽然还可以把自己传给子组件,(卧槽vue可没有这个啊 )  vue的传递值差不多,传方法就不用了,子组件可以掉 ...

  6. Vue--子组件互相传值,子组件来回传值,传值反复横跳

    Vue--子组件传值,子组件来回传值,子组件传值反复横跳 我不不仅要子组件之间直接传值,我还要传过去再传回来,传回来再传过去,子组件直接反复横跳 解决问题 给组件传值,并不知道改值的校验结果 同一个组 ...

  7. react 父组件向子组件传递函数

    这段时间一直在使用react,由于这react是单向数据绑定,总感觉有点不适用,毕竟之前一直都在使用angular,但学习还是要继续,做了一个迭代的项目,都差点忘记要总结一下这个react了,现在可以 ...

  8. react之路由

    功能:让用户从一个视图(组件)导航到另一个视图(组件) 前端路由是一套映射规则,在React中,是URL路径与组件的对应关系 使用React路由简单来说,就是配置路径和组件 路由的使用 1.安装路由 ...

  9. react ---- Router路由的使用和页面跳转

    React-Router的中文文档可以参照如下链接: http://react-guide.github.io/react-router-cn/docs/Introduction.html 首先,我们 ...

随机推荐

  1. xcode 老项目library not found for -libstdc++.6.0.9

    Xcode升级到Xcode10.0后,由于去掉陈旧的libstdc++库替换为libc++,libc++相对是苹果最新版的C++库,经过优化并全面支持C++11 下载libstdc++库,链接: ht ...

  2. Java日志体系(二)log4j

    1.1 简介 Log4j是一个由Java编写可靠.灵活的日志框架,是Apache旗下的一个开源项目: 使用Log4j,我们更加方便的记录了日志信息,它不但能控制日志输出的目的地,也能控制日志输出的内容 ...

  3. Python 内置函数 -- zip(), sorted(), filter()和map()

    内置函数1. zip() 打包(木桶效应)描述: zip() 函数用于将可迭代的对象作为参数, 将对象中对应的元素打包成一个个元组, 然后返回由这些元组组成的列表语法: zip([iterable, ...

  4. idea设置背景色和字体大小

    修改背景色  点击[File],选择[Settings]. 点击[Editor],选择[color Scheme]. 默认Scheme只有两种.Default是白色,Darcula是黑色   修改字体 ...

  5. gitbook组织管理书写

    1.git 强大的版本管理工作,也适合对书写内容的更新管理. 2.markdown git管理文本,所以书写要从docx格式转变成markdown. 而typora是一个比较好用markdown书写工 ...

  6. CentOS 7升级OpenSSH

    目录 下载openssh安装包 安装telnet 卸载旧的openssh 安装依赖 安装openssh 重启验证 关闭telnet服务 参考 下载openssh安装包 下载地址 wget https: ...

  7. 《JAVA语言》课问题汇总

    一.阅读相应教材,或者使用互联网搜索引擎,弄清楚反码.补码跟原码这几个概念,然后编写示例程序,对正数.负数进行各种位操作,观察输出结果,与手工计算的结果进行比对,看看Java中的数是采用上述哪种码表示 ...

  8. ubuntu linux环境下安装配置jdk和tomcat

    关于linux搭建服务器,ubuntu中jdk和tomcat的安装和配置 一.jdk的安装配置 1:去官网下载好自己需要的版本,注意,linux压缩文件通常以tar.gz结尾,别下载错了.本次我下载安 ...

  9. [转帖]PostgreSQL的用户、角色和权限管理

    PostgreSQL的用户.角色和权限管理 2018年05月18日 14:02:29 jerry-89 阅读数 6143 https://blog.csdn.net/eagle89/article/d ...

  10. redis 持久化之 RDB & AOF

    Redis 持久化实现方式 快照对数据某一时间点的完整备份.例如Linux 快照备份.Redis RDB.MySQL Dump. 日志将数据的所有操作都记录到日志中,需要恢复时,将日志重新执行一次.M ...