Code前端首页关于Code前端联系我们

一、先搞懂router view是干啥的?

terry 6小时前 阅读数 13 #Vue

在Vue项目里搞路由开发时,不少小伙伴会碰到“路由切换后组件没重新渲染、数据还留着旧的”这类麻烦事儿,这时候经常听到“给router - view加个key试试”的建议,那router - view加key到底有啥作用?哪些场景必须用?怎么选key才合理?今天咱们就把这些问题掰碎了聊聊~

router - view是Vue Router里的“路由出口”,就像个“占位符”,咱们在路由配置里写好哪个路径对应哪个组件,当路径匹配时,对应的组件就会被渲染到router - view所在的位置,比如配置了/home对应Home组件、/about对应About组件,页面里写<router - view></router - view>,访问不同路径时,这个位置就会动态换成对应的组件。

给router - view加key,核心作用是啥?

Vue渲染组件时,默认会“复用”相同的组件实例(毕竟复用能提升性能),但有些场景下,咱们不想要复用,得让组件“重新创建”,这时候key就起关键作用了——因为Vue会根据key判断两个节点是否“可复用”,key变了,就会销毁旧组件、创建新组件,给router - view加key,主要解决这两类问题:

强制组件实例“重建”,让生命周期重新执行

比如做“文章详情页”,路由是/article/:id,不管id是1还是2,渲染的都是ArticleDetail组件,默认情况下,Vue会复用ArticleDetail的实例,这就导致:从/article/1切到/article/2时,ArticleDetail的created、mounted这些生命周期钩子不会重新执行,如果数据是在created里请求的,那拿到的还是/article/1的数据,页面自然不更新。

这时候给router - view加个key,比如<router - view :key="$route.fullPath"></router - view>,因为/article/1和/article/2的fullPath不一样,key就不一样,Vue发现key变了,就会把旧的ArticleDetail组件销毁,重新创建新实例,这时候created、mounted这些钩子会重新执行,数据也能拿到最新的id对应内容。

解决路由切换后的“状态残留”问题

想象一下:组件里有个表单,用户填了一半切到其他路由,再切回来时,表单里的内容还在,这不是用户想要的,毕竟切路由相当于“换页面”,表单得清空重新填,但因为组件实例被复用了,状态也跟着保留下来。

给router - view加key后,组件重新创建,内部的data、表单状态都会被重置,自然就不会残留之前的内容了,再比如组件里有个弹窗组件,默认是关闭的,路由切换后弹窗突然是打开状态——加key让组件重建,就能避免这种尴尬。

哪些场景必须给router - view加key?

不是所有场景都需要加key,得看需求,这三类场景,加key几乎是“必须操作”:

同一路由组件,对应不同参数(动态路由场景)

最典型的就是“动态路由”,比如商品详情(/product/:id)、文章详情(/article/:id)、用户个人页(/user/:userId)这类场景,路由参数变了,但组件本身没换,这时候不加key,组件实例复用,数据和生命周期都不更新,页面肯定出问题。

路由切换后,需要“重置组件状态”

比如做“多步骤表单”,不同路由对应不同步骤(像/form/step1/form/step2),切换步骤后,上一步的输入内容得清空;或者组件里有依赖用户操作的临时状态(比如选中的选项、展开的菜单),路由切换后得恢复初始状态,这时候加key,让组件重建,状态自然就重置了。

组件依赖“全局状态/异步数据”,路由切换需重新计算

比如组件里的数据依赖用户权限(权限可能在路由切换后变化),或者依赖接口返回的动态配置,路由切换后,这些依赖可能变了,组件得重新获取数据、重新计算,但因为组件实例复用,生命周期不执行,数据就没法更新——加key强制重建,就能解决这个问题。

key的值怎么选才合理?

key的核心作用是“区分组件是否需要重建”,所以得选“能准确反映路由变化”的值,这几种选法最常用:

推荐用$route.fullPath

$route.fullPath包含了“路径 + 查询参数”(比如/list?page=1的fullPath就是完整的带参数路径),只要路由的路径、参数、查询参数有一个变化,fullPath就会变,key也跟着变,这种方式覆盖场景最全,大部分项目里用这个就够了,

<router - view :key="$route.fullPath"></router - view>

举个例子:列表页带搜索参数,从/list?page=1切到/list?page=2,fullPath变了,key变了,组件重建,就能重新请求第二页的数据。

按需组合关键参数(route.params.id + $route.query.sort)

如果只关心“部分参数”的变化,比如文章详情页只关心id,列表页只关心page,那可以把关键参数拼起来当key。

<router - view :key="$route.params.id + $route.query.sort"></router - view>

但这种方式要小心:如果有其他参数变化也需要组件重建,这种“按需组合”可能漏掉,比如列表页还有个filter参数,你没加到key里,那filter变化时key不变,组件不会重建,数据就没法更新,所以除非你明确知道“只有这些参数影响组件重建”,否则优先用fullPath更保险。

千万别用固定值或随机数

有人图省事,写:key="1"——这完全没用,因为key不变,组件还是复用;还有人用Math.random()当key,虽然每次key都变,但组件会频繁销毁重建,性能爆炸差,完全没必要,这两种写法,碰到了赶紧改!

不加key会踩哪些“大坑”?

如果该加key的时候没加,开发时很容易碰到这些让人头大的问题:

数据不更新,展示旧内容

路由参数都变了,组件里的数据请求还拿着旧参数,比如从/article/1切到/article/2,ArticleDetail组件的created里请求数据,结果因为实例复用,created没执行,请求还是基于id=1,页面显示的还是文章1的内容,用户一脸懵。

生命周期钩子“摆烂”不执行

组件里写了mounted钩子初始化图表、定时器,结果路由切换后,mounted根本不执行,图表还是旧的,定时器也没重新设置,功能直接失效。

状态残留,用户体验拉胯

表单输入的内容、弹窗的显示状态、下拉菜单的选中项,路由切换后还留在页面上,用户以为切到新页面了,结果看到旧状态,体验特别差,还容易造成误操作。

给router - view加key,这些细节要注意!

加key不是“随便加加”就行,得考虑性能、缓存这些细节:

性能权衡:别过度加key

加key会让组件销毁重建,频繁切换的话,性能肯定受影响,所以非必要场景别加!比如不同路由对应不同组件(/home对应Home,/about对应About),这种情况Vue本来就会销毁旧组件、创建新组件,加key纯属多余,还影响性能。

和keep - alive配合时,要更谨慎

如果router - view被keep - alive包裹(用来缓存组件实例,提升性能),这时候加key要特别注意——keep - alive是根据组件的name和key来判断是否缓存的,如果key选得不对,可能导致缓存失效,或者缓存了不该缓存的状态,比如你想缓存组件,但加了key导致每次都重建,那keep - alive就白用了,这时候得结合业务需求,平衡“缓存”和“重建”的关系。

确保key“变的时候真的变,不变的时候真不变”

选key的核心是“路由变化时key必须变,路由没变化时key不能变”,比如用fullPath,它能精准反映路由的所有变化;如果自己拼参数,得确保所有影响组件重建的参数都被包含进去,不然就会出现“该重建时没重建,不该重建时乱重建”的情况。

router - view的key,核心作用是控制组件实例是否复用,解决动态路由数据不更新、状态残留这些痛点,但要用对场景、选对key值,还要权衡性能,下次碰到路由切换后组件“不听话”的情况,不妨先检查下router - view的key加对了没~

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门