React面试题

655 阅读10分钟

思路

  • 讲(概念)说(用途)理(思路)列(优缺点)
  • 一句话解释 核心概念 方案对比
  • 知道流程(只会用)理解理念核心思路(还可以)有实际应用场景(棒)
  • 工程化即标准化,按照规范来做

1、React是什么? => 你对React的理解

  • React是一个网页UI框架,通过组件化的方式解决视图开发复用的问题,本质是一个组件化框架。
  • 核心思路=>
    • 声明式 => 更直观,便于组合
    • 组件化 => 视图拆分与模块复用
    • 通用性 => 一次学习,随处编写(靠虚拟dom实现)

2、为什么使用声明式(JSX)

  • jsx是javascript的语法扩展,结构类似XML,主要用于声明React元素
  • 对比
    • 模版 => 引入概念太多
    • 模版字符串 => 结构描述复杂,代码提示差
    • Json => 代码提示差

3、理解生命周期

  • componentWillMount() => 已弃用(在react异步渲染中会造成多次渲染)
  • componentWillUpdate() => 已弃用 (在react异步渲染中会出现暂停更新渲染)
  • componentWillReceiveProps() => 已弃用(性能问题,被下面这个生命周期替代)
  • componentDidmount() 组件加载完做某些请求
  • getDerivedStateFromProps() => props改变时更新state(父级组件渲染就会被调用)
  • shouldConponentUpdate() 通过对比值来确定是否重新渲染,用于性能优化
  • componentWillUnmount() 解除事件绑定,清理定时器等操作
  • getDerivedStateFromError() 报错了处理state状态
  • componentDidCatch() 捕获错误,上传服务端,不捕获报错了页面会白屏,渲染时的报错,只能componentDidCatch获取

异步请求放在componentDidmount中

4、组件渲染

  • 函数组件没有生命周期 => 任何情况下都会重新渲染, 可以通过memo优化(memo:跳过渲染组件的操作,直接复用最后一次渲染的结果)
  • class组件 => 如不实现shouldConponentUpdate函数,有两种情况会重新渲染(state值改变时,父组件props传入时)
  • PureComponent组件 => 默认实现shouldConponentUpdate函数,仅在state与state浅比较后有变更才会渲染

5、类组件与函数组件区别

共同点

  • 作为组件来说,二者在使用方式和最终呈现效果是一样的

不同点

  • 编程方式 => 类组件是基于面向对象编程,函数是函数式编程
  • 性能优化 => 类组件依靠shouldConponentUpdate,函数依靠Memo
  • 使用场景 => 现在是一样的,因为函数在hooks的加持下也有生命周期了
  • React主推函数式组件(why? a、this的模糊性 b、业务逻辑在生命周期中 c、组件代码缺乏标准的拆分模式)

6、如何设计React组件

  • 有状态组件 => 面向业务、功能丰富、复杂度高、复用性低
    • 容器组件 => 主要用于获取数据和组合组件、复用性低
    • 高阶 => 复用组件逻辑的高级技术
      • 高阶函数的参数是函数,执行后返回一个函数
      • 高阶组件的参数是组件,执行后返回一个组件函数
      • 高阶组件渲染劫持通过控制render函数修改输出内容,常见形式是显示加载元素(super.render(),获取渲染劫持原本的渲染结果)
      • 高阶组件缺陷 丢失静态函数,refs属性不能透传
  • 无状态组件 => 通用性强,复用率高
    • 代理组件(如对antd的button再封装,便于以后切换其他ui组件)
    • 样式组件(传入样式)
    • 布局组件(固定的布局)

7、setState是同步还是异步?

  • 为什么是异步的? => 性能优化,减少渲染次数,保持内部一致性,启用并发更新
  • react通过isBatchingUpdates(值为true/false)来控制是否是异步的
  • 异步场景 => react可以控制的,将多个操作放在一起更新
  • 同步场景 => react无法控制的,如原生事件(setTimeOut,addEventListener,setInInterval等)

8、跨组件通信 流行的做法是组件所有的能力都能通过props来控制

  • 父传子 => props传递state
  • 子传父 => 回调,实例 ref(不推荐)
  • 兄弟传值 => 父组件中转
  • 七大姑八大姨传值 => 1、使用Context Api,2、使用全局变量 3、状态管理mobx、redux

9、React状态管理

  • Mobx => 通过监听数据属性的方式触发渲染,响应式
  • Flux => 使用单向数据流来组合react组件的应用架构,项目结构简化了视图层的设计,明确了分工,数据与业务逻辑统一存放管理,使在大型架构项目中更容易管理,维护代码
  • Redux 是javascript的状态管理容器,他提供的状态管理实现了撤销、重做、实时编辑、时间旅行,优点:结果可预测,代码结构严格易维护,模块分离清晰
    • store 单一数据源,整个应用的state存在store中(UI状态)
    • Reducer 描述Action如何改变state,需要编写Reducer(业务逻辑)
    • Action 唯一可改变state的方法(事件)
    • Action -> Reducer -> store -> View

10、virtual dom(虚拟dom) react会初始化一个虚拟dom树,在状态变更后,触发虚拟dom的更改,再以此修改真实dom

  • 优点:性能好、防止xss攻击(窃取用户信息),可跨平台
  • 缺点:内存占用高(存了真实和虚拟两个dom),无法进行极致优化
  • react有两个函数
    • diff函数 计算变更前后虚拟dom的差异
    • 渲染函数 渲染dom树或差异点

11、diff算法

  • 是什么? => diff算法是指生成更新补丁的方式
  • 干什么? => 主要应用于虚拟dom树变化,更新真实dom
  • 流程 => 真实dom生成虚拟dom -> 对比新旧虚拟dom得到差异dom -> 更新真实dom -> 更新视图
  • 更新时机 => 发生在setState、hooks调用等操作
  • 遍历算法(同步的,不可以被打断) => 深度优先遍历算法 先从左子树纵向遍历,回溯再遍历右(复杂度为o(n^3))
  • 优化策略 => 优化o(n^3)至 o(n)
    • 树对比 => 对同一层节点比较,如果发现节点不存在则删除节点及其子节点
    • 组件对比 => 对组件类型进行比较,是就进行树比对,不是就放入补丁
    • 元素对比 => 同一层级的子节点可以通过标记key的方式进行对比
  • 优化代码
    • 根据diff算法的设计原则,应尽量避免跨层级节点移动。
    • 通过设置唯一 key 进行优化,尽量减少组件层级深度。因为过深的层级会加深遍历深度,带来性能问题。
    • 设置shouldComponentUpdate或者React.pureComponet减少 diff 次数。

12、React 16 Fiber架构

  • 为什么有fiber新架构 => 原老架构Stack Reconcilers有主线程的超时占用问题, 因为Stack Reconcilers是一个同步的递归过程,意味着一旦更新开始,根本停不下来。会造成卡顿。
    • Reconcilers => 通过抽离公共函数与diff算法使声明式渲染、自定义组件、state、生命周期等实现跨平台工作。
  • Fiber架构核心:(可中断,可恢复,优先级,异步)fiber更新任务都会被赋予一个优先级,新任务来临时会检查优先级,如果比现有更高,会中断现有,执行高优先级,之后再恢复原执行

13、React的渲染流程 渲染过程分为React16以前和16以后,

  • 16以采用的是stack,渲染流程包括挂载、更新、卸载,stack是一个同步递归的过程
  • 16以采用的是fiber,渲染过程包括render和commit,fiber是按照优先级策略,多任务模式,在动画,手势中性能提升明显

14、React渲染异常的后果

  • 白屏 出现了javascript错误(为什么白屏:因为react内部状态被破坏,导致应用崩溃)
  • 如何处理 捕获错误
    • getDerivedStateFromError() 报错了处理state状态
    • componentDidCatch()
    • 跳转到兜底页面(报警)
    • 预防(工程化,按标准来)

15、性能优化

  • lighthouse 收集性能数据(google分析网页性能工具)
  • performance google推出主要用于查询javascript执行栈的耗时时间,确认函数卡顿点
  • 优化
    • loading
    • 骨架屏
    • CDN(利用最靠近用户的服务器获取静态资源)
    • ssr(服务端渲染,就是在服务器端将对页面进行渲染生成html文件,将html页面传递给浏览器)
    • 核心同步加载
    • 非核心异步加载
    • 图片使用懒加载

16、避免重复渲染

  • 长列表 => 使用虚拟滚动可以很好的优化
  • 重复渲染
    • 使用purecomponent
    • 使用memo
    • 使用shouldcomponentupdate
    • 合理的使用箭头函数,因为箭头函数会生存一个新函数,导致重新渲染

17、如何提升代码可维护性

  • 可分析 => 能快速定位线上问题,工具可以使用ESLint,Sentry
  • 可改变 => 代码易于迭代
  • 稳定性 => 避免修改代码对线上的影响
  • 易测试 => 易于发现代码的潜在问题
  • 标准化 => 前端工程化,按标准写代码

18、hooks使用限制

  • 不要在循环、条件或者嵌套函数中调用hooks
    • hooks是基于数组实现的,在调用时按顺序加入数组中,如果使用循环条件等,容易导致数组取值错位
  • 在react的函数组件中调用hooks
  • 为什么限制
    • 组件之间难以复用逻辑(只能使用高阶组件,状态管理)
    • 生命周期与业务逻辑耦合

19、useEffect和useLayoutEffect区别 共同点

  • 都是用于处理副作用(改变dom,设置订阅,操作定时器等) 不同点
  • 大多数情况用useEffect(异步),如果你的页面因代码引起了闪烁使用useLayoutEffect,直接操作dom或引起dom样式更新也使用useLayoutEffect(在所有dom变更后最后同步渲染useLayoutEffect)

20、hooks设计模式

常见问题

  • 获取上一轮props或state的不方便(使用useRef记录上一次)

  • 以前是通过生命周期来思考逻辑,hooks是通过副作用

  • 使用useMemo可以更精细化控制,因为memo并不能控制组件内部共享状态的变化

  • 由于函数组件每次渲染都会重新执行,常量应该放在函数外部,避免每次创建,如果常量是函数,且需要使用组件内部的变量,那么要使用useCallback缓存函数

  • useeffect第二个参数是浅比较,尽量不要传引用类型,会判断为不相等

  • 自定义hook (抽离公共逻辑)

export default function useCountDown (initCount = 10) {
 const [count, setCount] = useState(initCount)
 useEffect(() => {
     let timeChange = setTimeout(() => {
         setCount(count - 1)
       }, 1000)
   }, [count]
 )
 return {count}
}
//使用
const {count} = useCountDown()

21、React-Router

  • hash和history
  • 提供Router、MemoryRouter(app)容器
  • 提供路由匹配功能Route、Redirect、Switch
  • 提供react-router-dom的Link、NavLink、Deeplinking(app页面跳转)

如何防止用户在编写内容时误触返回? 使用react-router-dom提供的useHistory钩子来判断是返回还是前进history.action === 'PUSH'/'POP'

22、React用到的工具

  • 创建项目 => create-react-app(简单不易扩展,可用react-app-rewired扩展)
  • 路由 => React-Router
  • 样式 => css、scss、less
  • 基础组件 => Antd
  • 功能组件 => monent、echarts、axios、react-quill(富文本)、react-dnd(实现拖拽)、video-react(视频播放)、react-pdf-viewer(预览pdf)、
  • 状态管理 => mobx、redux
  • 构建工具 => webpack、esbuild、vite
  • 代码规范检查 => EsLint
  • 发布 => 可以使用s3-plugin-webpack完成文件上传到cdn

23、启发式算法

  • React16expirationTimes模型只能区分是否>=expirationTimes决定节点是否更新。
  • React17lanes模型可以选定一个更新区间,并且动态的向区间中增减优先级,可以处理更细粒度的更新。