快来加入我们吧!
"小和山的菜鸟们",为前端开发者提供技术相关资讯以及系列基础文章。为更好的用户体验,请您移至我们官网小和山的菜鸟们 ( https://xhs-rookies.com/ ) 进行学习,及时获取最新文章。
"Code tailor" ,如果您对我们文章感兴趣、或是想提一些建议,微信关注 “小和山的菜鸟们” 公众号,与我们取的联系,您也可以在微信上观看我们的文章。每一个建议或是赞同都是对我们极大的鼓励!
面试系列不定期更新,请随时关注
前言
本篇专栏重点在于讲解面试中 框架(react、vue) 的面试题内容。
注意: 本篇专栏至只会涉及到重点内容,并不会进行拓展。某些题目需要拓展知识点的,我们会将拓展内容、整体详细信息放置与每个题目的最前面,可以自行查看。
框架(react、vue)
框架 |
---|
虚拟 DOM(什么是虚拟 DOM,为什么会出现,用来干什么,哪些框架里面有?) |
双向绑定的实现原理,以及在 vue 中是如何实现的 |
react 中的 diff 算法 |
react 和 vue 的区别 |
react 中 redux 思想以及使用 |
react 常用的生命周期及其执行顺序 |
react hooks 的作用到底是什么 |
react router 什么作用,你怎么使用的 |
react 中类组件和函数组件的区别 |
redux 和 vuex 两者的认识和区别 |
题目解析
虚拟 DOM
Virtual DOM
是一种编程概念。在这个概念里, UI 以一种理想化的,或者说“虚拟的”表现形式被保存于内存中,并通过如 ReactDOM
等类库使之与“真实的” DOM
同步。
当你在渲染一个 div 时,其实例属性可多达 298 个(Chrome 下,每个浏览器实现不同),没有 VIrtual DOM
,我们每次进行视图更新时,将旧 dom 元素移除,挂载新 dom 元素,这会导致我们消耗大量的内存和 CPU 资源。而 VIrtual dom
的存在则是为了帮助我们只针对修改的部分进行渲染,这也同样使得我们可以从属性操作、事件处理和手动 DOM 更新这些在构建应用程序时必要的操作中解放出来。
VIrtual DOM
具体表现形式,其实就是通过 JavaScript
来描述 DOM
结构,本质即通过 JavaScript
做了一层 DOM
映射
更多请见 Virtual DOM 概念
具体映射方式请查看 Virtual DOM映射方式
diff 算法
在某一时间节点调用 React 的 render()
方法,会创建一棵由 React 元素组成的树。在下一次 state
或 props
更新时,相同的 render()
方法会返回一棵不同的树。React 需要基于这两棵树之间的差别来判断如何高效的更新 UI
,以保证当前 UI
与最新的树保持同步。
此算法有一些通用的解决方案,即生成将一棵树转换成另一棵树的最小操作次数。然而,即使使用最优的算法,该算法的复杂程度仍为 O(n3)
,其中 n
是树中元素的数量。
如果在 React
中使用该算法,那么展示 1000
个元素则需要 10
亿次的比较。这个开销实在是太过高昂。于是 React
在以下两个假设的基础之上提出了一套 O(n)
的启发式算法:
- 两个不同类型的元素会产生出不同的树;
- 开发者可以通过设置
key
属性,来告知渲染哪些子元素在不同的渲染下可以保存不变;
正是基于此设计概念,所以 React diff
算法只对同层进行比较,故将复杂度降低到 O(n)
而其体现形式即如下:
- 对比不同类型的元素(当根节点为不同类型的元素时,
React
会拆卸原有的树并且建立起新的树) - 对比同一类型的元素(仅对比更新有改变的属性)
- 对比同一类型的组件元素(组件实例会保持不变,因此可以在不同的渲染时保持
state
一致) - 对子节点进行递归(默认情况下,
React
会同时遍历两个子元素的列表;当产生差异时,生成一个mutation
)
对子节点的递归涉及到我们为什么要为子元素设置 key ?即帮助 React 使用 key 来匹配原有树上的子元素以及最新树上的子元素。至于为什么不用下标作为 key ,我想读者加以思考便会知道
由于 React
依赖启发式算法,因此当以下假设没有得到满足,性能会有所损耗。
- 该算法不会尝试匹配不同组件类型的子树。如果你发现你在两种不同类型的组件中切换,但输出非常相似的内容,建议把它们改成同一类型。在实践中,我们没有遇到这类问题。
Key
应该具有稳定,可预测,以及列表内唯一的特质。不稳定的key
(比如通过Math.random()
生成的)会导致许多组件实例和DOM
节点被不必要地重新创建,这可能导致性能下降和子组件中的状态丢失。
react 常用的生命周期及其执行顺序
挂载
constructor()
static getDerivedStateFromProps()
render()
componentDidMount
更新
static getDerivedStateFromProps()
shouldComponentUpdate()
render()
getSnapshotBeforeUpdate()
componentDidUpdate()
卸载
componentWillUnmount
钩子函数详细使用说明请前往 React.Component
react redux
首先要明白 redux 是 JavaScript 应用程序的可预测状态管理工具,其本身与 react 无关,react - redux 将它们两联系起来的
而学习 react redux 需先明白 redux 的工作原理。Redux 是一个经典的发布订阅器,它帮我们用一个变量存储所有的 State,并且提供了发布功能来修改数据,以及订阅功能来触发回调(但是回调之后干嘛?自己解决)。
- 首先明确与 React 产生关联的是 React-Redux 这个库
- Redux 的原理就是一个发布订阅器,帮我们用一个变量存储所有的 State,并且提供了发布功能来修改数据,以及订阅功能来触发回调
- 而 React-Redux 的作用就是订阅 Store 里数据的更新,他包含两个重要元素,Provider 和 connect 方法
- Provider 的作用就是通过 Context API 把 Store 对象注入到 React 组件上去
- 而 connect 方法就是一个高阶组件,在高阶组件里通过订阅 Store 中数据的更新,从而通过调用 setState 方法来触发组件更新
更多使用请见:redux
react hooks
它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。
- 使用 state
- 状态逻辑复用
它出现的动机更多的还是说在组件之间复用状态逻辑很难,纵然我们已有高阶组件,render props 可以去做这样的事情,但二者或多或少多存在一些问题
例如,高阶组件在做逻辑复用时
- 无法清晰的标识数据的来源
- props 可能会被覆盖
而 render props 则很容易导致
- 嵌套地狱
所以说 react hooks 的出现更多的是解决了状态逻辑复用的完整性
更多钩子函数请前往 Hooks
react router
react router 期望在不刷新页面的情况下,根据不同的路径展示不同的组件
react router 的三个核心组件即
- 路由器: BrowserRouter 和 HashRouter
- 路由匹配器:Switch 和 Route
- 路由导航:Link、NavLink 和 Redirect
使用的话大家自行发挥就好
react 中类组件和函数组件的区别
在 hooks 出来之前,其实函数组件和类组件的区别在于
区别 | 函数组件 | 类组件 |
---|---|---|
生命周期 | 无 | 有 |
this | 无 | 有 |
state | 无 | 有 |
实例化 | 需要 | 不需要 |
而 hook 之后就仁者见仁,智者见智了,推荐看这篇由 react 核心开发者 dan 写的 类组件和函数组件的区别
下节预告
下节我们将为大家带来 网络及存储
的面试题解,敬请期待!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。