面试之React篇

144 阅读7分钟
  1. 什么是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

通过这些属性就能找到下一个执行目标

  1. React的特性

    React采用Immedite的设计思想,特性有单向数据绑定、jsx、虚拟dom、声明式编程、component

  2. 说说你对虚拟dom的理解

    虚拟dom是对真实的dom的一层抽象,实际是通过babel转化成React.CreateElement的形式,节点类型有原子节点、文本节点、类组件节点、函数组件节点

    优缺点

    减少重排与重绘

    更加容易维护

    带来跨平台的可能性

  3. React的生命周期

创建阶段:

    constructor
    getDeriveStateFromProps
    render
    componentDidMount
    

更新阶段

    getDeriveStateFromProps
    shouldComponentUpdate
    getSnapShotBefore
    render
    componentDidUpdate

卸载

    componentWillUnmount
  1. setState的执行机制

原生dom、setTimeout中为同步,其他为异步,可以通过回调函数获取最新值。

  1. React的事件机制
  • React 上注册的事件最终会绑定在document这个 DOM 上,而不是 React 组件对应的 DOM(减少内存开销就是因为所有的事件都绑定在 document 上,其他节点没有绑定事件)
  • React 自身实现了一套事件冒泡机制,所以这也就是为什么我们 event.stopPropagation()无效的原因。
  • React 通过队列的形式,从触发的组件向父组件回溯,然后调用他们 JSX 中定义的 callback
  • React 有一套自己的合成事件 SyntheticEvent
  1. React时间绑定的方式
  • constructor里通过bind的方式
  • render里通过bind的方式
  • render里的箭头函数
  • 定义时,采用箭头函数(最优)
  1. React组件的通信方式
  • props 回调函数
  • 父组件作为中间件
  • context refs
  • redux mobox recoil等
  1. 说说对react 中key的理解

  2. react refs的理解

  3. 类组件跟函数式组件的区别

    区别:

  • 函数式组件无状态组件,除了useState
  • 函数是组件无生命周期,除了useEffect
  • 调用方式不同,函数式组件直接调用,类组件需要实例化
  • 函数式组件中没有this的多次调用
  1. 受控组件&非受控组件

全程响应外部控制的组件成为受控组件,推荐使用受控组件进行表单的开发

  1. 高阶组件HOC

输入一个组件返回一个组件,用于组件的封装,现已被Hook取代

  1. Hook解决了什么问题

    状态逻辑的复用,自定义的hook用于更好的进行封装,避免了嵌套地狱

  2. 简单谈一下redux

    redux三大原则: 唯一数据源、state只读、纯函数修改

    store、dispatch分发action、触发reducer对store进行修改,getState获取数据

  3. 说说你对redux中间件的理解

    redux本身的操作是不支持异步的,所以就有了redux中间件,类似于redux-chunk、redux-logger,主要是对dispatch的过程进行封装,原理是所有的中间件都被放置在一个chain的数组里嵌套执行,最后执行了dispatch

  4. react-redux

    两大核心: Provider、connect

    provider是将store放在顶层,connection是将store、dispatch放置到props上

  5. 说说对react-router的理解

    react-router主要有BrowserRouter跟HashRouter两种,分别对应history路由跟hash路由,常用组件还有

  • route: 路由匹配组件
  • Link: 跳转组件
  • NavLink: 在link的基础之上加了样式
  • switch组件 匹配第一个组件后,后续不再继续匹配

相关hook, useHistory、useParams、useLocation,底层都是通过context进行传值

  1. 什么是Immutable

    计算机中,一旦创建,就无法被更改的数据,对于Immutable对象进行任何的添加、删除、修改等操作都会返回一个新的Immutable对象,原理是持久化数据结构,采用结构共享

    Immutable.js is方法,collection,list,map,set等数据结构,用于性能优化。

  2. React render的原理

    触发时机: setState useState(值必须发生变化) 父组件的state变化导致子组件变化

  3. react diff的过程

    三个层级的策略:

    tree层级:同级比较、只有删除创建,无移动的情况 component层级: 同一个类的组件才进行比较 element层级: key作为唯一的标识,插入、移动、删除

    遍历节点 遍历过程中三个变量 index(新集合的遍历下标) oldIndex: 当前节点在旧数组的下标 maxIndex(在新集合的访问过的节点中,其在老集合的最大下标)

    oldIndex > maxIndex => maxIndex = oldIndex

    oldIndex = max continue

    oldIndex < maxIndex 移动到index

    React更新的两个阶段: render阶段 -> 生成新的fiber(可中断) commit阶段: 更新dom(不可中断)

  4. 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

  5. react性能优化的手段

  • 避免内联函数
  • React.fragment避免额外节点
  • Immutable.js
  • 组件懒加载 React.lazy
  • 事件绑定方式采用箭头函数
  • 服务端渲染 nuxt.js
  • useCallback useMemo
  1. useEffect、useLayoutEffect的区别

useEffect 主要是在组件渲染到屏幕之后延迟执行,默认情况下,effect在每轮渲染结束后运行

useLayoutEffect它会在所有的dom变更之后同步调用effect,可以使用它来读取dom布局并同步触发渲染