-
什么是react Fiber, 它解决了什么问题?
fiber是React 16新增的数据结构,由于之前的React采用自顶而下的更新策略,占用了主线程,导致交互、动画无法实时的进行响应,所以react对任务就那些了分拆,把渲染过程分成了多个子任务,每次做一部分,执行完之后,挂起,将时间控制权交给主线程,其中对应每个任务的更新单元就是fiber。
react主要做了以下操作:
1)为每个任务增加了优先级,优先级高的任务可以中断低优先级的任务。然后再重新,注意是重新执行优先级低的任务
2)增加了异步任务,调用requestIdleCallback api,浏览器空闲的时候执行
3)dom diff树变成了链表,一个dom对应两个fiber(一个链表),对应两个队列,这都是为找到被中断的任务,重新执行
从架构的角度来看,fiber是对react核心算法(调和)的重写
从编码角度来看,fiber是react定义的数据结构,它是Fiber树结构的子节点,实际为一个对象。
Fiber把渲染更新过程拆分成多个子任务,每次只做一小部分,做完看是否还有剩余时间,如果有继续下一个任务;如果没有,挂起当前任务,将时间控制权交给主线程,等主线程不忙的时候在继续执行
即可以中断与恢复,恢复后也可以复用之前的中间状态,并给不同的任务赋予不同的优先级,其中每个任务更新单元为 React Element 对应的 Fiber节点
实现的上述方式的是requestIdleCallback方法
window.requestIdleCallback()方法将在浏览器的空闲时段内调用的函数排队。这使开发者能够在主事件循环上执行后台和低优先级工作,而不会影响延迟关键事件,如动画和输入响应
首先 React 中任务切割为多个步骤,分批完成。在完成一部分任务之后,将控制权交回给浏览器,让浏览器有时间再进行页面的渲染。等浏览器忙完之后有剩余时间,再继续之前 React 未完成的任务,是一种合作式调度。
该实现过程是基于 Fiber节点实现,作为静态的数据结构来说,每个 Fiber 节点对应一个 React element,保存了该组件的类型(函数组件/类组件/原生组件等等)、对应的 DOM 节点等信息。
作为动态的工作单元来说,每个 Fiber 节点保存了本次更新中该组件改变的状态、要执行的工作。
每个 Fiber 节点有个对应的 React element,多个 Fiber节点根据如下三个属性构建一颗树:
// 指向父级Fiber节点
this.return = null
// 指向子Fiber节点
this.child = null
// 指向右边第一个兄弟Fiber节点
this.sibling = null
通过这些属性就能找到下一个执行目标
-
React的特性
React采用Immedite的设计思想,特性有单向数据绑定、jsx、虚拟dom、声明式编程、component
-
说说你对虚拟dom的理解
虚拟dom是对真实的dom的一层抽象,实际是通过babel转化成React.CreateElement的形式,节点类型有原子节点、文本节点、类组件节点、函数组件节点
优缺点减少重排与重绘
更加容易维护
带来跨平台的可能性
-
React的生命周期
创建阶段:
constructor
getDeriveStateFromProps
render
componentDidMount
更新阶段
getDeriveStateFromProps
shouldComponentUpdate
getSnapShotBefore
render
componentDidUpdate
卸载
componentWillUnmount
- setState的执行机制
原生dom、setTimeout中为同步,其他为异步,可以通过回调函数获取最新值。
- React的事件机制
- React 上注册的事件最终会绑定在document这个 DOM 上,而不是 React 组件对应的 DOM(减少内存开销就是因为所有的事件都绑定在 document 上,其他节点没有绑定事件)
- React 自身实现了一套事件冒泡机制,所以这也就是为什么我们 event.stopPropagation()无效的原因。
- React 通过队列的形式,从触发的组件向父组件回溯,然后调用他们 JSX 中定义的 callback
- React 有一套自己的合成事件 SyntheticEvent
- React时间绑定的方式
- constructor里通过bind的方式
- render里通过bind的方式
- render里的箭头函数
- 定义时,采用箭头函数(最优)
- React组件的通信方式
- props 回调函数
- 父组件作为中间件
- context refs
- redux mobox recoil等
-
说说对react 中key的理解
-
react refs的理解
-
类组件跟函数式组件的区别
区别:
- 函数式组件无状态组件,除了useState
- 函数是组件无生命周期,除了useEffect
- 调用方式不同,函数式组件直接调用,类组件需要实例化
- 函数式组件中没有this的多次调用
- 受控组件&非受控组件
全程响应外部控制的组件成为受控组件,推荐使用受控组件进行表单的开发
- 高阶组件HOC
输入一个组件返回一个组件,用于组件的封装,现已被Hook取代
-
Hook解决了什么问题
状态逻辑的复用,自定义的hook用于更好的进行封装,避免了嵌套地狱
-
简单谈一下redux
redux三大原则: 唯一数据源、state只读、纯函数修改
store、dispatch分发action、触发reducer对store进行修改,getState获取数据
-
说说你对redux中间件的理解
redux本身的操作是不支持异步的,所以就有了redux中间件,类似于redux-chunk、redux-logger,主要是对dispatch的过程进行封装,原理是所有的中间件都被放置在一个chain的数组里嵌套执行,最后执行了dispatch
-
react-redux
两大核心: Provider、connect
provider是将store放在顶层,connection是将store、dispatch放置到props上
-
说说对react-router的理解
react-router主要有BrowserRouter跟HashRouter两种,分别对应history路由跟hash路由,常用组件还有
- route: 路由匹配组件
- Link: 跳转组件
- NavLink: 在link的基础之上加了样式
- switch组件 匹配第一个组件后,后续不再继续匹配
相关hook, useHistory、useParams、useLocation,底层都是通过context进行传值
-
什么是Immutable
计算机中,一旦创建,就无法被更改的数据,对于Immutable对象进行任何的添加、删除、修改等操作都会返回一个新的Immutable对象,原理是持久化数据结构,采用结构共享
Immutable.js is方法,collection,list,map,set等数据结构,用于性能优化。
-
React render的原理
触发时机: setState useState(值必须发生变化) 父组件的state变化导致子组件变化
-
react diff的过程
三个层级的策略:
tree层级:同级比较、只有删除创建,无移动的情况 component层级: 同一个类的组件才进行比较 element层级: key作为唯一的标识,插入、移动、删除
遍历节点 遍历过程中三个变量 index(新集合的遍历下标) oldIndex: 当前节点在旧数组的下标 maxIndex(在新集合的访问过的节点中,其在老集合的最大下标)
oldIndex > maxIndex => maxIndex = oldIndex
oldIndex = max continue
oldIndex < maxIndex 移动到index
React更新的两个阶段: render阶段 -> 生成新的fiber(可中断) commit阶段: 更新dom(不可中断)
-
jsx转换成真实dom的过程
babel 判断jsx首字母 大写 对象 小写 dom标签 -> react dom render挂载
react.createElement的形式 有type props children 转化成虚拟dom 主要有原生节点、文本节点、函数节点、类节点等
具体的流程总结:
babel将jsx转换成React.createElement, createElement对key、ref等特殊的props进行处理,并获取defaultProps进行赋值,并对传入的孩子节点进行处理,构造一个虚拟的dom对象,ReactDom执行render将生成好的虚拟dom渲染到指定的容器,其中采用了批处理、事务等机制对特定的浏览器进行了优化,最终转换成真实的dom
-
react性能优化的手段
- 避免内联函数
- React.fragment避免额外节点
- Immutable.js
- 组件懒加载 React.lazy
- 事件绑定方式采用箭头函数
- 服务端渲染 nuxt.js
- useCallback useMemo
- useEffect、useLayoutEffect的区别
useEffect 主要是在组件渲染到屏幕之后延迟执行,默认情况下,effect在每轮渲染结束后运行
useLayoutEffect它会在所有的dom变更之后同步调用effect,可以使用它来读取dom布局并同步触发渲染