Skip to content

getDerivedStateFromError

React 组件生命周期方法之一,用于处理组件在渲染过程中出现的错误。它是从 React 16.6 版本引入的。

当组件的子组件抛出错误时,或者在组件的生命周期方法中发生错误时,React 将调用getDerivedStateFromError方法。这个方法是一个静态方法,需要在组件类中实现。它接收一个错误对象作为参数,并返回一个更新的状态对象

jsx
class ErrorBoundary extends React.Component {
    static getDerivedStateFromError(error) {
        // 返回一个新的状态对象,用于展示错误信息
        return { hasError: true }
    }

    constructor(props) {
        super(props)
        this.state = { hasError: false }
    }

    render() {
        if (this.state.hasError) {
            return <div>发生了错误。</div>
        }
        return this.props.children
    }
}

// 使用 ErrorBoundary 组件包裹可能会出错的子组件
;<ErrorBoundary>
    <ChildComponent />
</ErrorBoundary>

使用Hooks要遵守哪些原则?

  1. 只在最顶层使用 Hook (不要在循环,条件或嵌套函数中调用 Hook, 确保总是在你的 React 函数的最顶层调用他们。)

  2. 只在 React 函数中调用 Hook (在 React 的函数组件、自定义 Hook 中调用 Hook)

    为什么要加这些限制? React中每个组件都有一个对应的 FiberNode对象,这个对象上有个属性叫 memoizedState,在函数组件中,fiber.memoizedState存储的就是Hooks单链表,单链表中每个hook节点没有名字和key,只能通过顺序来记录他们的唯一性。 如果在循环、条件或者嵌套中使用hook,当组件更新时,这个hooks顺序会乱套,单链表的稳定性就破坏了。

React Fiber它的目的是解决什么问题?

React15 的 StackReconciler 方案由于递归不可中断问题,如果 Diff 时间过长(JS计算时间),会造成页面 UI 的无响应(比如输入框)的表现,vdom 无法应用到 dom 中。

为了解决这个问题,React16 实现了新的基于 requestIdleCallback 的调度器(因为 requestIdleCallback 兼容性和稳定性问题,自己实现了 polyfill),通过任务优先级的思想,在高优先级任务进入的时候,中断 reconciler。

为了适配这种新的调度器,推出了 FiberReconciler,将原来的树形结构(vdom)转换成 Fiber 链表的形式(child/sibling/return),整个 Fiber 的遍历是基于循环而非递归,可以随时中断。

更加核心的是,基于 Fiber 的链表结构,对于后续(React 17 lane 架构)的异步渲染和 (可能存在的)worker 计算都有非常好的应用基础

怎么防止HTML被转义?

dangerouslySetInnerHTML

react 函数式组件有没有生命周期

在 React 中,函数式组件是一种更简洁和轻量级的组件形式,通常以函数的形式定义,而不是类。函数式组件在 React 16.8 版本引入了 Hooks 之后变得更加强大,Hooks 提供了一种在函数式组件中使用状态和其他 React 特性的方式。

在传统的意义上,函数式组件并没有像类组件那样的生命周期方法。类组件有一系列生命周期方法,如 componentDidMount、componentDidUpdate 和 componentWillUnmount,用于处理组件的挂载、更新和卸载等阶段。

然而,使用 Hooks,函数式组件可以使用一些特定的 Hook 函数来实现类似生命周期的功能。以下是一些常用的 Hook 函数:

  • useState:用于在函数式组件中使用状态。
  • useEffect:在组件渲染完成后执行副作用操作,相当于 componentDidMount、componentDidUpdate 和 componentWillUnmount 的组合。
  • useContext:用于从 React Context 中获取上下文。
  • useReducer:在函数式组件中使用 Redux 风格的状态管理。
  • useCallback 和 useMemo:用于性能优化,避免不必要的重新计算。

React如何加载异步组件

jsx
import React, { Suspense } from 'react'

const LazyComponent = React.lazy(() => import('./LazyComponent'))

function App() {
    return (
        <div>
            <Suspense fallback={<div>Loading...</div>}>
                <LazyComponent />
            </Suspense>
        </div>
    )
}

react 为什么需要合成事件?

  • 跨浏览器兼容:合成事件首先抹平了浏览器之间的兼容问题,另外这是一个跨浏览器原生事件包装器,赋予了跨浏览器开发的能力;
  • 性能优化:对于原生浏览器事件来说,浏览器会给监听器创建一个事件对象。如果你有很多的事件监听,那么就需要分配很多的事件对象,造成高额的内存分配问题。React 通过合成事件实现了事件委托机制, 对于合成事件来说,有一个事件池专门来管理它们的创建和销毁,当事件需要被使用时,就会从池子中复用对象,事件回调结束后,就会销毁事件对象上的属性,从而便于下次复用事件对象 。

react 合成事件特点

  • 我们在 jsx 中绑定的事件(demo中的handerClick,handerChange),根本就没有注册到真实的dom上。是绑定在document上统一管理的。
  • 真实的dom上的click事件被单独处理,已经被react底层替换成空函数。
  • react并不是一开始,把所有的事件都绑定在document上,而是采取了一种按需绑定,比如发现了onClick事件,再去绑定document click事件。

为什么推荐使用函数式组件?

代码简洁:避免this绑定和类语法冗余 逻辑复用:自定义Hooks比HOC更灵活 性能优化:Hooks提供更细颗粒度的控制(如useMemo) 未来兼容:新特性(如并发模式)优先支持Hooks

Hooks的限制和突破

规则:只能在函数顶层调用Hooks 原理:依赖调用顺序的链表结构记录状态 解决方案:使用eslint-plugin-react-hooks强制规范

事件合成设计目的与核心原理

  1. 跨浏览器一致性

统一不同浏览器的事件处理接口(如event.target的行为) 修复浏览器兼容性问题(如IE事件模型差异)

2 .性能优化

事件委托:将事件绑定到根节点(React 17+ 为应用根DOM),而非每个子元素 事件池化(Event Pooling):复用事件对象,减少内存开销

  1. 扩展能力

支持自定义事件类型(如 onDoubleClick) 实现高级功能(如事件优先级调度)

diff 算法

React采用逐层递归比较,但不会跨层级追踪节点变化,当父节点类型相同时,递归比较其他子节点

为什么列表必须使用key?

帮助React识别元素身份,在顺序变化时高效复用DOM节点,避免以下问题:

  • 不必要的子组件重新渲染
  • 表单元素状态错乱(如输入框内容错位)

Fiber

  1. Fiber的诞生背景

    1. 旧版协调算法瓶颈
      • 递归不可中断:同步遍历整个虚拟DOM树,长时间占用主线程
      • 卡顿问题:复杂组件树更新导致掉帧(如大型列表、动画场景)
    2. 目标
      • 实现增量渲染,支持异步可中断的更新
  2. Fiber核心设计思想

    1. 时间切片

      • 将渲染任务拆分为多个小任务(Fiber节点)
      • 利用浏览器空闲时段(requestIdleCallback)分片执行
    2. 优先级调度

      • 用户交互(如输入)优先于数据更新(如API响应)
    3. 可恢复工作单元

      • 保存中间状态,允许暂停/恢复渲染流程
  3. Fiber节点数据结构

    • 每个Fiber节点对应一个组件实例或DOM节点,包含以下核心属性:
  4. Fiber双缓冲机制

    React维护两颗Fiber树已确保更新无冲突

    • Current Tree:当前已渲染的UI对应的Fiber树
    • WorkInProgress Tree:正在构建的新Fiber树

    切换流程:更新完成后,WorkInProgress Tree树变为Current树

如何实现可中断更新

通过链表结构存储Fiber节点,记录遍历进度。每次处理一个Fiber后检查剩余时间片,不足时保存当前进度,将控制权交还浏览器

协调阶段和提交阶段的区别

协调阶段负责计算变更(可中断),提交阶段执行DOM操作(同步不可中断)

.React核心设计思想

组件化设计

  • 原子化构建:UI分解为独立的功能单元(如函数式组件/类组件)
  • 组合模式:通过props嵌套实现组件树结构
  • 隔离型:每个组件维护自身状态和样式(CSS-in-JS生态支持)
  • 复用机制:高阶组件(HOC)与自定义Hooks实现逻辑复用

声明式编程范式

  • 状态驱动:UI=f(state)的数学表达式(无需手动操作DOM)
  • 抽象渲染:开发者专注描述目标状态,框架处理渲染细节
  • 幂等性保证:相同state必定输出相同视图(确定性原则)

高效更新引擎

  • 虚拟DOM层:内存中轻量级DOM表示(对象树结构)
  • Diff算法优化:启发式O(n)复杂度比较策略(基于树遍历策略)
  • 批量更新策略:自动合并setState操作(异步更新策略)
  • 渲染流水线:Fiber架构实现可中断渲染(并发模式)

单向数据控制

  • 严格数据通道:props自上而下传递(严禁子级逆向修改)
  • 状态托管:通过Context/Redux实现跨层级通信
  • 副作用隔离:Hooks机制约束副作用边界(useEffect依赖链)

这些原则使React具备:高维护性(组件解耦)、高性能(智能更新)、可预测性(数据流透明)。