React面试题
1.react理解
React,用于构建用户界面的 JavaScript 库,只提供了 UI 层面的解决方案 ,是渐进式框架
特性: JSX 语法 , 单向数据绑定 , 虚拟 DOM , 声明式编程 ,组件化开发
2.react-router 里的 标签和 标签有什么区别?
react-router 接管了其默认的链接跳转行为,与传统的页面跳转有区别的是,Link 的 “跳转” 行为只会触发相匹配的对应的页面内容更新,而不会刷新整个页面。
link做了哪些事:1.有onclick就执行onclick,2.click的时候阻止a标签默认事件,3.根据跳转href用history跳转,此时只是链接变了,并没有刷新页面
3.React Jsx转换成真实DOM过程?
首先我们知道Jsx代码是不会被浏览器识别的,最终都会转化为 React.createElement 形式,babel实现这个过程
createElement函数对key和ref等特殊的props进行处理,并获取defaultProps对默认props进行赋值,并且对传入的孩子节点进行处理,最终构造成一个虚拟DOM对象
ReactDOM.render将生成好的虚拟DOM渲染到指定容器上,其中采用了批处理、事务等机制并且对特定浏览器进行了性能优化,最终转换为真实DOM
4.React Router的理解,原理?常用的Router组件有哪些?
路由的本质就是页面的URL发生改变时,页面的显示结果可以根据URL的变化而变化,但是页面不会刷新
react-router主要分成了几个不同的包(这一块先不写了)
常用router组件:
BrowserRouter、HashRouter : 路由模式history,hash
route: Route用于路径的匹配,然后进行组件的渲染
Link、NavLink: 通常路径的跳转是使用Link组件 NavLink是在Link基础之上增加了一些样式属性,例如组件被选中时,发生样式变化 ( activeStyle , activeClassName )
redirect:路由重定向
switch: swich组件的作用适用于当匹配到第一个组件的时候,后面的组件就不应该继续匹配
5.react生命周期
组件挂载时
当组件实例被创建并插入DOM时,其生命周期调用顺序如下:
constructor()
static getDerivedStateFromProps()
render()
componentDidMount()
组件更新时
当组件的props或state发生变化时会触发更新。组件更新的生命周期调用顺序如下:
static getDerivedStateFromProps()
shouldComponentUpdate()
render()
getSnapshotBeforeUpdate()
componentDidUpdate()
组件卸载时
当组件从DOM中移除时会调用如下方法
componentWillUnmount()
6.react新生命周期取代了哪些?为什么?
React 新的生命周期方法主要是为了支持 Fiber 架构中的三个新概念而设计的: fiber节点,异步渲染,可中断性
getDerivedStateFromProps(静态方法) 取代了componentWillMount和 componentWillReceiveProps
getSnapshotBeforeUpdate 取代了componentWillUpdate
getDerivedStateFromProps 中禁止了组件去访问 this.props, 由于 this.props 可能在任何时刻发生变化,所以计算出来的 state 对象可能会与旧的 state 对象相同,从而导致状态更新无效和不必要的组件重新渲染。 在 getDerivedStateFromProps 方法中应该始终使用参数中的 nextProps,而不是 this.props。这样可以保证组件状态的计算是基于最新的 props,从而避免了状态更新无效和渲染性能的问题。
getSnapshotBeforeUpdate 方法是在组件的 render 方法被调用后,在更新 DOM 之前被调用的 ,也就是说在 getSnapshotBeforeUpdate 中读取到的 DOM 元素信息是可以保证与componentDidUpdate 中一致的。
7.Fiber架构的理解?解决了什么问题?
在 React 16 之前,VirtualDOM 的更新采用的是Stack架构实现的,也就是循环递归方式。不过,这种对比方式有明显的缺陷,就是一旦任务开始进行就无法中断,如果遇到应用中组件数量比较庞大,那么VirtualDOM 的层级就会比较深,带来的结果就是主线程被长期占用,进而阻塞渲染、造成卡顿现象。
fiber:为了避免出现卡顿等问题,我们必须保障在执行更新操作时计算时不能超过16ms,如果超过16ms,就需要先暂停,让给浏览器进行渲染,后续再继续执行更新计算。而Fiber架构就是为了支持“可中断渲染”而创建的。 解决了react在渲染大量dom节点出现丢帧的问题
React Fiber 与浏览器的交互流程如下图。
从架构角度:fiber是对react核心算法的重写(调和过程)
从编码角度:fiber是react内部定义的一种数据结构,是fiber树结构的节点单位,react16新架构下的虚拟dom
主要操作:
为每个增加了优先级,优先级高的任务可以中断低优先级的任务。然后再重新,注意是重新执行优先级低的任务
增加了异步任务,调用requestIdleCallback api,浏览器空闲的时候执行
dom diff树变成了链表,一个dom对应两个fiber(一个链表),对应两个队列,这都是为找到被中断的任务,重新执行
在 Fiber 架构中,React 将组件的更新过程分为两个阶段:reconciliation 和 commit。其中 reconciliation 阶段主要负责计算出更新后的 Virtual DOM 树,并确定哪些组件需要进行重新渲染,而 commit 阶段则负责将 Virtual DOM 树的变化映射到真实的 DOM 上。
总结:相比传统的Stack架构,Fiber 将工作划分为多个工作单元,每个工作单元在执行完成后依据剩余时间决定是否让出控制权给浏览器执行渲染。 并且它设置每个工作单元的优先级,暂停、重用和中止工作单元。 每个Fiber节点都是fiber tree上的一个节点,通过子、兄弟和返回引用连接,形成一个完整的fiber tree。
8.react有状态组件和无状态组件的理解及使用场景?、
有状态组件
特点:
是类组件
有继承
可以使用 this
可以使用 react 的生命周期
使用较多, 容易频繁触发生命周期钩子函数, 影响性能
内部使用 state, 维护自身状态的变化, 有状态组件根据外部组件传入的 props 和自身的 state 进行渲染
使用场景:
需要使用到状态的
需要使用状态操作组件的(无状态组件的也可以实现新版本 react hooks 也可实现)
总结:
类组件可以维护自身的状态变量, 即组件的 state, 类组件还有不同的生命周期方法, 可以让开发者能够在组件的不同阶段(挂载、更新、卸载), 对组件做更多的控制。类组件则既可以充当无状态组件, 也可以充当有状态组件。当一个类组件不需要管理自身状态时, 也可称为无状态组件。
无状态组件
特点:
不依赖自身的状态 state
可以是类组件或者函数组件
可以完全避免使用 this 关键字(由于使用的是箭头函数事件无需绑定)
有更高的性能, 当不需要使用生命周期钩子时, 应该首先使用无状态函数组件
组件内部不维护 state, 只根据外部组件传入的 props 进行渲染的组件, 当 props 改变时, 组件重新渲染
使用场景
组件不需要管理 state, 纯展示
优点:
简化代码、专注于 render
组件不需要被实例化, 无生命周期, 提升性能, 输出(渲染)只取决于输入(属性), 无副作用
视图和数据的解耦分离
缺点:
无法使用 ref
无生命周期方法
无法控制组件的重渲染, 因为无法使用 shouldComponentUpdate 方法, 当组件接受到新的属性时则会重渲染
9. React 的事件合成?
所有事件都是委托在id = root的DOM元素中(网上很多说是在document中,17版本不是了);
在应用中所有节点的事件监听其实都是在id = root的DOM元素中触发;
React自身实现了一套事件冒泡捕获机制;
React实现了合成事件SyntheticEvent;
React在17版本不再使用事件池了(网上很多说使用了对象池来管理合成事件对象的创建销毁,那是16版本及之前);
事件一旦在id = root的DOM元素中委托,其实是一直在触发的,只是没有绑定对应的回调函数;
10.React组件之间如何通信?
1.父组件向子组件通讯:
父组件可以向子组件传入props的方式,向子组件进行通讯。
2.子组件向父组件通讯:
props+回调的方式,父组件向子组件传递props进行通讯,此props为作用域为父组件自身的函数,子组件调用该函数,将子组件想要传递的信息,作为参数,传递到⽗组件的作⽤域中。
3.兄弟组件通信:
兄弟组件之间的传递,则父组件作为中间层来实现数据的互通,通过使用父组件传递
例:组件A – 传值 --> 父组件 – 传值 --> 组件B
4.跨层级通讯:
Context 设计⽬的是为了共享那些对于⼀个
组件树⽽⾔是“全局”的数据,
使用context提供了组件之间通讯的一种方式,可以共享数据,其他数据都能读取对应的数据
例如当前认证的⽤户、主题或⾸选语⾔,对于跨越多层的全局数据通过 Context 通信再适合不过。
5.发布订阅者模式:
发布者发布事件,订阅者监听事件并做出反应,我们可以通过引⼊event模块进⾏通信。
6.全局状态管理工具:
借助Redux或者Mobx等全局状态管理⼯具进⾏通信,这种⼯具会维护⼀个全局状态中⼼Store,并根据不同的事件产⽣新的状态。
11.React服务端渲染怎么做?原理是什么?
服务端渲染(SSR): 指由服务侧完成页面的 HTML 结构拼接的页面处理技术,发送到浏览器,然后为其绑定状态与事件,成为完全可交互页面的过程
服务端渲染解决的问题:1.SEO由于搜索引擎爬虫抓取工具可以直接查看完全渲染的页面 2.加速首屏加载,解决首屏白屏问题
React如何做服务端渲染?
手动搭建SSR框架
使用成熟的SSR框架,如next.js
实现原理:
node server 接收客户端请求,得到当前的请求url 路径,然后在已有的路由表内查找到对应的组件,拿到需要请求的数据,将数据作为 props、context或者store 形式传入组件
然后基于 react 内置的服务端渲染方法 renderToString()把组件渲染为 html字符串在把最终的 html 进行输出前需要将数据注入到浏览器端
浏览器开始进行渲染和节点对比,然后执行完成组件内事件绑定和一些交互,浏览器重用了服务端输出的 html 节点,整个流程结束