React面试葵花宝典之三

71、React组件返回值

、在 React 中,组件的返回值取决于组件的类型,通常有以下几种情况:

1. 函数组件的返回值

函数组件返回的是 JSX 或 null

const MyComponent = () => {return <div>Hello, React!</div>;
};

如果需要条件渲染,可以返回 null

const MyComponent = ({ show }) => {return show ? <div>Visible</div> : null;
};

2. 类组件的返回值

类组件的 render 方法返回 JSX:

class MyComponent extends React.Component {render() {return <div>Hello, Class Component!</div>;}
}

同样可以返回 null

class MyComponent extends React.Component {render() {return null;}
}

3. Fragment(片段)

React 允许返回多个元素而不需要额外的 DOM 包裹:

const MyComponent = () => {return (<><h1>Title</h1><p>Description</p></>);
};

<></>React.Fragment 的简写。

4. 数组(Fragments 之外的多元素返回)

可以返回数组来渲染多个元素:

const MyComponent = () => {return [<li key="1">Item 1</li>,<li key="2">Item 2</li>,<li key="3">Item 3</li>,];
};

5. React.createElement

JSX 最终会被转换成 React.createElement

const MyComponent = () => {return React.createElement('div', null, 'Hello, React!');
};

6. Portal

如果需要将组件渲染到 document.body 之外的 DOM 节点,可以返回 ReactDOM.createPortal

import ReactDOM from 'react-dom';const MyComponent = () => {return ReactDOM.createPortal(<div>Portal Content</div>,document.getElementById('portal-root'));
};

7. Suspense

如果组件使用 React.Suspense 进行懒加载,它的返回值可能是 Suspense 组件:

import React, { Suspense, lazy } from 'react';const LazyComponent = lazy(() => import('./LazyComponent'));const MyComponent = () => {return (<Suspense fallback={<div>Loading...</div>}><LazyComponent /></Suspense>);
};

总结

React 组件的返回值通常是:

  1. JSX 元素<div>...</div>
  2. React.Fragment<></>React.Fragment
  3. 数组(必须包含 key
  4. null(用于条件渲染)
  5. React.createElement(底层实现)
  6. Portal(使用 ReactDOM.createPortal
  7. Suspense 组件(用于懒加载)

这些返回值决定了组件如何在 React 组件树中渲染。

72.monorepo是什么用来做什么的

Monorepo是“monolithic repository”的缩写,也就是将多个项目或模块放在同一个代码仓库中。这和传统的每个项目一个仓库的方式不同。
为什么需要monorepo
大型项目、多包管理的库(如Babel、React)、需要跨团队协作的情况。
对比传统的多仓库方式,比如代码重复、依赖管理复杂、协作效率低等问题。Monorepo如何解决这些问题,比如共享代码、统一构建工具、简化依赖管理等。
Monorepo(单一代码仓库)是一种将多个项目或模块存储在同一个代码仓库中的代码管理策略。它的核心目标是简化跨项目协作、共享代码和统一工程化流程,尤其适合中大型团队或复杂项目。以下是其核心概念和用途的详细解析:


一、Monorepo 的核心特点

  1. 统一代码库

    • 所有相关项目(如前端、后端、工具库)存放在同一仓库中。

    • 示例目录结构:

      monorepo/├── apps/│   ├── web-app/      # 前端应用│   └── mobile-app/   # 移动端应用├── packages/│   ├── utils/        # 公共工具库│   └── ui-kit/       # 共享 UI 组件库└── package.json      # 根目录配置
      
  2. 共享依赖与代码

    • 模块间可直接引用本地代码,无需发布到包管理器(如 npm)。
    • 避免代码重复,例如多个项目共用工具函数或 UI 组件。
  3. 统一工具链

    • 集中管理构建、测试、代码规范等配置(如 ESLint、TypeScript、Jest)。
    • 一键执行跨项目操作(如同时构建所有应用)。
  4. 原子化提交(Atomic Commits)

    • 跨项目的代码变更可在一次提交中完成,确保版本一致性。
    • 便于追踪代码变更的影响范围。

二、Monorepo 的典型使用场景

  1. 多应用共享代码

    • 例如:Web 端、移动端、后台管理系统共用同一套业务逻辑或组件库。
  2. 微前端架构

    • 多个子应用(Micro Frontends)在同一个仓库中开发,便于协调和集成。
  3. 多包管理(Monorepo 的经典场景)

    • 开源项目如 BabelReactVue 3 使用 Monorepo 管理核心库、插件、文档等。
    • 示例:React 仓库包含 reactreact-domscheduler 等包。
  4. 全栈项目

    • 前后端代码同仓,方便接口联调和数据模型同步。

三、Monorepo 的优势

优势说明
代码复用跨项目共享代码,减少重复开发(如工具函数、组件、配置)。
依赖管理简化统一管理第三方依赖版本,避免版本冲突。
跨项目重构修改公共代码后,可立即验证所有依赖项目,降低破坏性变更风险。
统一 CI/CD集中配置构建、测试、部署流程,提升自动化效率。
协作效率提升开发者更容易理解项目全貌,减少跨仓库沟通成本。

四、Monorepo 的挑战与解决方案

挑战解决方案
仓库体积膨胀使用 Git 稀疏检出(Sparse Checkout)或按需克隆。
构建性能增量构建(如 Turborepo)、缓存优化、任务并行化。
权限管理通过目录级权限控制(如 Git Submodules 或自定义工具)。
工具链复杂度使用成熟 Monorepo 工具(如 NxTurborepoRush)。

五、主流 Monorepo 工具

  1. Lerna

    • 传统 Monorepo 工具,适合多包发布(如 Babel 使用 Lerna)。
    • 需配合 Yarn Workspaces 或 npm Workspaces 使用。
  2. Nx

    • 功能强大,支持增量构建、依赖图可视化、分布式任务执行。
    • 适合大型企业级项目。
  3. Turborepo

    • 高性能构建缓存,无缝集成主流框架(Next.js、React Native)。
    • 配置简单,适合中小型项目。
  4. Yarn/PNPM Workspaces

    • 内置的轻量级 Monorepo 支持,管理依赖和跨包链接。

六、何时选择 Monorepo?

  • 适合场景

    • 项目间高度耦合,需要频繁共享代码。
    • 团队规模较大,需统一开发规范。
    • 希望简化依赖管理和跨项目协作。
  • 不适合场景

    • 小型独立项目,无需代码共享。
    • 团队技术栈差异大,难以统一工具链。

七、示例:React 的 Monorepo 结构

React 的仓库是经典案例,其结构如下:

react/├── packages/│   ├── react/          # React 核心│   ├── react-dom/      # DOM 渲染器│   ├── scheduler/      # 调度器│   └── ...             # 其他子包├── scripts/            # 构建脚本└── package.json        # 根目录配置

通过 Monorepo,React 团队可以同步更新核心库与相关模块,确保版本一致性。


总结

Monorepo 通过集中化管理代码共享,解决了多仓库协作的碎片化问题,尤其适合复杂项目或需要高度协作的团队。选择时需权衡项目规模、工具链支持与团队能力,合理使用工具(如 Turborepo 或 Nx)可大幅降低维护成本。

73.React中什么叫并发渲染具体表现是什么

并发渲染(Concurrent Rendering)是 React 18 引入的核心特性,它通过可中断的异步渲染机制,让 React 应用在处理复杂更新时保持高响应性。以下是其核心原理与具体表现:
并发渲染的本质是让 React 具备多任务协作能力
并发渲染通过时间切片,任务 优先级调度 ,可中断渲染,实现react的多任务协作能力,将多个任务实习切片,并按照优先级渲染,在处理高优先级人物时可以中断渲染


一、并发渲染的核心机制

  1. 时间切片(Time Slicing)

    • 将渲染任务拆分为多个可中断的微任务块(通常每块 5ms 左右)。
    • 浏览器主线程在每块任务之间可以处理更高优先级的操作(如用户点击、动画)。
  2. 任务优先级调度

    • 通过 Lane 模型 区分更新优先级(如用户输入 > 数据加载 > 非紧急渲染)。
    • 高优先级任务可“插队”低优先级任务,避免界面卡顿。
  3. 可中断的渲染流程

    • 渲染过程(Render Phase)可被中断,React 会暂存中间状态,后续恢复时继续处理。
    • 提交阶段(Commit Phase)保持同步,确保 DOM 更新原子性。

二、具体表现

1. 更流畅的交互体验
  • 输入响应优先
    当用户在输入框打字时,React 会优先处理输入事件,延迟其他低优先级渲染(如搜索结果列表的更新),确保输入不卡顿。

  • 示例

    function SearchBox() {const [query, setQuery] = useState('');const deferredQuery = useDeferredValue(query); // 延迟更新return (<><input value={query} onChange={(e) => setQuery(e.target.value)} /><Results query={deferredQuery} /> // 低优先级渲染</>);
    }
    
2. 后台预渲染
  • 提前准备 UI
    在用户执行可能触发渲染的操作前(如悬停按钮),React 可提前在后台渲染内容,提升后续操作的响应速度。

  • 示例

    function App() {const [tab, setTab] = useState('home');return (<div><button onMouseOver={() => startTransition(() => setTab('about'))}>About</button><Suspense fallback={<Loader />}><Content tab={tab} /></Suspense></div>);
    }
    
3. 批量非紧急更新
  • 合并低优先级更新
    通过 startTransitionuseDeferredValue 将非紧急更新(如搜索建议、图表重绘)标记为“可延迟”,避免阻塞关键渲染。

  • 示例

    const [input, setInput] = useState('');
    const [search, setSearch] = useState('');const handleInput = (text) => {setInput(text); // 高优先级:立即更新输入框startTransition(() => {setSearch(text); // 低优先级:延迟更新搜索结果});
    };
    
4. 更智能的 Suspense 配合
  • 流式加载与错误边界
    结合 Suspense,并发渲染可实现逐步加载组件或数据,优先显示已就绪内容(如骨架屏),同时处理加载状态和错误。

三、与传统同步渲染的对比

场景同步渲染并发渲染
用户输入时触发渲染输入卡顿,渲染阻塞事件循环输入流畅,渲染任务被中断或延迟
同时处理多个更新按顺序执行,可能产生界面冻结按优先级调度,高优先级任务优先
复杂组件树渲染长时间占用主线程,导致掉帧分片执行,保持主线程可响应

四、开发者如何利用并发渲染

  1. 使用并发特性 API

    • startTransition:标记非紧急更新。
    • useTransition:获取过渡状态(如加载指示器)。
    • useDeferredValue:延迟派生值的更新。
  2. 优化组件性能

    • 通过 React.memouseMemo 减少不必要的渲染。
    • 拆分大型组件树,利用 Suspense 分块加载。
  3. 避免阻塞渲染

    • 避免在渲染阶段执行耗时操作(如复杂计算、同步网络请求)。

五、底层实现:Fiber 架构

  • 链表结构:Fiber 节点构成双向链表,支持渲染过程的暂停与恢复。
  • 工作循环:通过 requestIdleCallback(或 polyfill)在浏览器空闲时段执行任务。
  • 优先级标记:使用 31 位的 Lane 模型精细控制任务调度。

总结

并发渲染的本质是让 React 具备多任务协作能力,通过智能调度渲染任务,在保持界面流畅的同时处理复杂更新。其表现包括:

  • 用户交互无卡顿
  • 高优先级任务即时响应
  • 后台预加载与延迟渲染
  • 更平滑的过渡效果

74.React Reconciler 协调器

React Reconciler是React内部的一个核心部分,负责协调(reconciliation)过程。协调是React用来比较新旧虚拟DOM树,找出差异并高效更新实际DOM的算法。React的协调器不仅仅处理虚拟DOM,还涉及到组件的生命周期、状态更新等。
Reconciler的主要职责。可能包括:

  1. 虚拟DOM的创建和更新:当组件的状态或props变化时,Reconciler会生成新的虚拟DOM树,并与旧的进行比较,找出需要更新的部分。
  2. Diff算法:这是协调过程中的关键,用来高效地找出差异。React的Diff算法基于两个假设:不同类型的元素会产生不同的树,以及通过key属性来识别稳定的子元素。
  3. 调度更新:React可能会将更新分成多个小任务,使用时间分片(time slicing)和优先级调度(如并发模式中的Suspense)来避免阻塞主线程,保持应用的响应性。
  4. 副作用处理:比如处理组件的生命周期方法(componentDidMount, componentDidUpdate等),或者函数组件中的useEffect钩子。
  5. 当setState被调用时,Reconciler会创建一个新的虚拟DOM树,然后与旧的进行比较,找出需要更新的节点,生成一个副作用列表(effect list),然后提交(commit)这些变更到实际的DOM中。
  6. 调度器(Scheduler)和Reconciler。调度器负责安排任务的优先级和执行时机,而Reconciler负责处理组件的更新和协调。
  7. React Reconciler 是 React 的核心模块之一,负责协调(Reconciliation)过程,即高效更新 UI 的关键机制。以下是其核心要点:

1. 核心职责

  • 虚拟 DOM 的协调:当组件状态或 props 变化时,Reconciler 生成新的虚拟 DOM 树,并与旧树对比(Diff 算法),找出最小变更集。

  • Diff 算法优化:基于两个假设:

    • 类型差异:不同类型的元素(如 <div> 变为 <span>)会销毁旧子树并重建。
    • Key 稳定性:通过 key 标识子元素,减少不必要的节点复用错误。
  • 调度与优先级:在并发模式下,将更新拆分为可中断的“任务”,优先处理高优先级更新(如用户交互),避免阻塞主线程。

  • 副作用管理:处理生命周期(如 componentDidUpdate)和 Hook 副作用(如 useEffect),生成并提交变更到真实 DOM。


2. Fiber 架构

React 16 引入的 Fiber 重构了 Reconciler,使其支持:

  • 增量渲染:将渲染拆分为多个可中断/恢复的“工作单元”(Fiber 节点),提升大型应用响应速度。
  • 并发模式:通过时间分片(Time Slicing)和任务优先级(Lane 模型)实现异步可中断更新。
  • 双向链表结构:Fiber 节点构成链表,支持深度优先遍历的暂停与回溯,优化协调过程。

3. 协调流程

  1. Render 阶段(可中断):

    • 对比新旧 Fiber 树,生成副作用列表(如插入、更新、删除)。
    • 使用 Diff 算法标记变更,不直接操作 DOM。
  2. Commit 阶段(不可中断):

    • 遍历副作用列表,批量更新真实 DOM。
    • 触发生命周期和 Hook 的副作用(如 useLayoutEffect)。

4. 与渲染器解耦

  • Reconciler 是平台无关的抽象层,与具体渲染器(如 React DOM、React Native)分离。
  • 渲染器负责将 Reconciler 的指令转换为平台特定操作(如 DOM 修改或原生组件更新)。

5. 性能优化

  • Key 的合理使用:列表渲染时,唯一且稳定的 key 减少不必要的元素重建。
  • 批量更新:合并多次 setState,避免重复渲染。
  • 组件优化:通过 React.memoshouldComponentUpdate 跳过无关组件的协调。

示例:Key 的重要性

// 无 key:列表顺序变化可能导致状态错乱(如输入框内容)
{items.map(item => <div>{item.text}</div>)}// 有 key:React 正确识别元素,优化复用
{items.map(item => <div key={item.id}>{item.text}</div>)}

总结

React Reconciler 通过虚拟 DOM 的智能对比、Fiber 的异步调度机制,以及跨平台渲染的抽象,实现了高效、灵活的 UI 更新。理解其原理有助于编写高性能 React 应用(如合理使用 key、优化渲染逻辑)。

75.React——Scheduler调度器

在 React 中,Scheduler 是一个用于协调任务调度的库,它管理不同优先级的任务,以确保 React 在主线程上的渲染不会阻塞关键用户交互。它是 React 并发模式(Concurrent Mode)的核心部分。


1. Scheduler 的作用

Scheduler 主要用于任务优先级管理,它可以:

  • 让高优先级任务(如用户输入)优先执行
  • 让低优先级任务(如页面渲染)延后执行
  • 让任务分批执行,防止长时间阻塞主线程

2. Scheduler API

React 通过 scheduler 包提供了一些 API 来控制任务的调度:

(1)scheduleCallback

用于调度一个任务,并根据优先级决定何时执行:

import { unstable_scheduleCallback, unstable_NormalPriority } from 'scheduler';unstable_scheduleCallback(unstable_NormalPriority, () => {console.log('执行一个普通优先级的任务');
});

可选优先级:

  • unstable_ImmediatePriority(最高,立即执行)
  • unstable_UserBlockingPriority(次高,用户交互)
  • unstable_NormalPriority(默认)
  • unstable_LowPriority(低)
  • unstable_IdlePriority(最低,浏览器空闲时执行)

(2)shouldYield

用于检查是否应该让出控制权,避免长时间占用主线程:

import { unstable_shouldYield } from 'scheduler';function heavyTask() {while (true) {if (unstable_shouldYield()) {console.log('主线程需要执行更高优先级任务,暂停当前任务');break;}// 执行计算任务...}
}

(3)getCurrentPriorityLevel

获取当前执行任务的优先级:

import { unstable_getCurrentPriorityLevel } from 'scheduler';console.log(unstable_getCurrentPriorityLevel()); // 返回当前任务的优先级

3. Scheduler 在 React 中的应用

(1)React 并发模式(Concurrent Mode)

Scheduler 主要用于 React 并发模式,以支持时间切片(Time Slicing) ,使得 React 渲染不会长时间阻塞主线程。例如:

function handleClick() {React.startTransition(() => {setState(expensiveComputation());});
}

startTransition 内部,React 可能会使用 Scheduler 让任务分批执行。

(2)提高用户体验

Scheduler 可以让高优先级任务(如输入响应)优先执行,避免 UI 卡顿。例如:

import { unstable_scheduleCallback, unstable_UserBlockingPriority } from 'scheduler';input.addEventListener('input', (event) => {unstable_scheduleCallback(unstable_UserBlockingPriority, () => {console.log('处理输入事件');});
});

4. 总结

  1. Scheduler 负责 React 任务调度,优化渲染任务的执行顺序。
  2. 它提供任务优先级管理,如 ImmediatePriorityUserBlockingPriority
  3. 它支持时间切片(Time Slicing) ,避免长时间阻塞主线程,提高 UI 流畅度。
  4. Scheduler 在 React 并发模式中发挥重要作用,比如 startTransition 内部使用了它。

如果面试官深入问,你可以补充 Scheduler 的工作原理、如何配合 requestIdleCallback 以及它在 React 18 并发渲染中的作用。

76.React18新特性——Concurrent Mode 并发模式 多个任务交替进行

React 18 的 Concurrent Mode(并发模式) 是 React 核心架构的重大升级,旨在通过可中断、优先级驱动的渲染机制,提升复杂应用的响应速度和用户体验。以下是其核心要点与面试回答方向:


一、核心目标

  • 解决阻塞渲染问题:传统同步渲染会阻塞主线程,导致用户交互卡顿(如输入延迟)。并发模式通过时间切片(Time Slicing) 将渲染任务拆分为可中断的微任务,优先响应用户操作。
  • 智能调度更新:根据任务优先级(如用户输入 > 数据加载 > 动画)动态调整渲染顺序,确保高优先级任务即时处理。
  • 支持后台预渲染:提前准备即将显示的 UI(如悬停时预加载组件),减少用户感知的等待时间。

二、关键特性与 API

1. 自动批处理(Automatic Batching)
  • 机制:React 18 默认将多个状态更新合并为单一渲染(包括 Promise、setTimeout 等异步操作),减少不必要的重复渲染。

  • 示例

    // React 17:setTimeout 内更新会触发两次渲染
    setTimeout(() => {setCount(1);setFlag(true);
    }, 1000);// React 18:自动批处理,仅一次渲染
    
2. 过渡更新(Transitions)
  • APIstartTransitionuseTransition

  • 作用:区分紧急更新(如输入反馈)与非紧急更新(如搜索结果),延迟后者以避免阻塞交互。

  • 示例

    const [isPending, startTransition] = useTransition();const handleSearch = (query) => {// 紧急:立即更新输入框setInput(query);// 非紧急:延迟更新搜索结果startTransition(() => {setSearchQuery(query);});
    };return <div>{isPending ? 'Loading...' : <Results />}</div>;
    
3. 延迟值(Deferred Values)
  • APIuseDeferredValue

  • 作用:派生值的“降级”更新,保持界面响应。适用于耗时计算或大型列表渲染。

  • 示例

    const deferredList = useDeferredValue(heavyList);
    return <List items={deferredList} />; // 延迟渲染,允许高优先级任务插队
    
4. Suspense 增强
  • 服务端渲染(SSR)支持:结合 lazySuspense 实现流式 HTML 传输,逐步加载组件并优先显示已就绪内容。

  • 示例

    <Suspense fallback={<Skeleton />}><Comments /> // 异步加载的评论组件
    </Suspense>
    
5. 新的 Root API
  • createRoot:替代 ReactDOM.render,启用并发特性。

    // React 17
    ReactDOM.render(<App />, document.getElementById('root'));// React 18
    const root = ReactDOM.createRoot(document.getElementById('root'));
    root.render(<App />);
    

三、底层原理

  • Fiber 架构升级:利用双向链表结构(Fiber 节点)实现可中断渲染,支持回溯和任务恢复。
  • Lane 模型:通过 31 位二进制位表示任务优先级,精细控制调度逻辑。
  • 协作式多任务:在浏览器空闲时段执行渲染任务(类似 requestIdleCallback),避免主线程阻塞。

四、性能优化场景

  1. 输入防抖:用户连续输入时,优先渲染输入框内容,延迟处理搜索请求。
  2. 页面切换预加载:鼠标悬停在导航按钮时,后台预加载目标页面的组件或数据。
  3. 大型列表渲染:使用 useDeferredValue 分块渲染,避免界面冻结。

五、迁移与注意事项

  • 渐进式采用:并发特性可逐步集成,无需重写整个应用。
  • 副作用处理:注意 useEffect 和生命周期钩子可能因渲染中断而多次执行,需确保幂等性。
  • 严格模式:React 18 的严格模式会故意双渲染组件,帮助发现副作用问题。

六、与传统模式对比

场景传统模式并发模式
用户输入响应可能被长任务阻塞高优先级更新优先处理,输入流畅
多个更新竞争顺序执行,可能导致卡顿按优先级调度,动态插队
复杂组件树渲染长时间占用主线程分片渲染,保持界面可交互

总结

React 18 的 Concurrent Mode 通过可中断渲染智能调度,使应用具备“多任务处理”能力,显著提升用户体验。开发者应重点掌握:

  • 核心 APIstartTransitionuseDeferredValueSuspense
  • 优化场景:区分紧急/非紧急更新,预加载关键资源
  • 底层机制:Fiber 架构与 Lane 模型的作用

理解并发模式不仅有助于应对面试,更能为构建高性能 React 应用提供坚实基础。

77.React18新特性——自动批处理 Automatic Batchin

React 18 新特性 —— 自动批处理(Automatic Batching)

自动批处理(Automatic Batching) 是 React 18 引入的一项优化,它可以自动地将多个状态更新合并,减少渲染次数,提高性能。


1. 什么是批处理(Batching)?

在 React 18 之前,批处理只发生在React 事件处理函数内部:

import { useState } from 'react';function App() {const [count, setCount] = useState(0);const [flag, setFlag] = useState(false);const handleClick = () => {setCount(count + 1);setFlag(!flag);// 在 React 17 及之前:只触发 1 次重新渲染(批处理)};console.log('组件渲染'); // 只会执行一次return <button onClick={handleClick}>{count.toString()}</button>;
}

但在异步任务(如 setTimeoutPromise)中,React 17 及之前不会进行批处理:

setTimeout(() => {setCount(count + 1);setFlag(!flag);// 在 React 17 及之前:触发 2 次重新渲染
}, 1000);

2. React 18 自动批处理(Automatic Batching)

在 React 18 中,所有的状态更新都会自动批处理,无论它们在哪个上下文中触发!
包括异步代码setTimeoutPromisefetch 等)。

示例:React 18 自动批处理

import { useState } from 'react';function App() {const [count, setCount] = useState(0);const [flag, setFlag] = useState(false);setTimeout(() => {setCount((prev) => prev + 1);setFlag((prev) => !prev);// React 18:只会触发 1 次渲染}, 1000);console.log('组件渲染'); // React 18 只执行 1 次return <div>{count.toString()}</div>;
}

React 17 及之前:触发 2 次渲染
React 18:触发 1 次渲染


3. 取消自动批处理

如果在某些情况下你不想让 React 自动合并更新,可以使用 flushSync 强制立即更新:

import { flushSync } from 'react-dom';function handleClick() {flushSync(() => {setCount((c) => c + 1);});flushSync(() => {setFlag((f) => !f);});// 这里会触发 2 次渲染
}

flushSync 适用于:

  • 需要在某个状态更新后立即获取最新 DOM 的情况
  • 需要精确控制渲染顺序的情况

4. 自动批处理的优势

减少不必要的渲染,提高性能
提升开发体验,减少状态更新导致的 UI 闪烁
统一行为,在同步和异步任务中都适用


5. 总结

  • 批处理(Batching) :React 会合并多个状态更新,减少渲染次数。
  • React 18 以前:仅在 React 事件处理函数中批处理,异步任务不会批处理。
  • React 18 自动批处理:所有任务(同步 & 异步)都批处理,减少不必要的渲染。
  • flushSync:如果需要强制立即更新,可以使用 flushSync

这个特性让 React 代码更高效,避免不必要的重渲染,是 React 18 重要的优化之一!

78.React18新特性——流式 SSR

React 18 新特性 —— 流式 SSR(Streaming Server-Side Rendering)

流式 SSR(Streaming Server-Side Rendering) 是 React 18 提供的一种优化的服务端渲染(SSR)方式,它允许服务器在数据准备好后逐步发送 HTML,而不是等待所有数据加载完再返回完整页面。


1. 传统 SSR vs. 流式 SSR

(1)传统 SSR 的问题

在 React 18 之前,SSR 采用的是阻塞式渲染

  • 服务器需要等所有数据加载完成,然后一次性返回完整 HTML。
  • 如果某个组件的数据请求较慢,会导致整个页面的加载延迟。
  • 用户在收到 HTML 之前,会一直看到空白页面。

示例(React 17 SSR):

import { renderToString } from 'react-dom/server';
import App from './App';const html = renderToString(<App />);
res.send(`<!DOCTYPE html><html><body>${html}</body></html>`);
  • renderToString 阻塞执行,直到 App 及其所有子组件的内容完全准备好。

(2)React 18 的流式 SSR

React 18 提供了非阻塞的流式渲染

  • HTML 按块(chunks)发送,优先展示可用的 UI。
  • 可以提前渲染静态内容,等数据准备好再填充动态内容。
  • 提高首次内容可见(FCP) ,减少白屏时间。

示例(React 18 流式 SSR):

import { renderToPipeableStream } from 'react-dom/server';
import App from './App';export default function handler(req, res) {const { pipe } = renderToPipeableStream(<App />, {onShellReady() {res.setHeader('Content-Type', 'text/html');pipe(res); // 立即开始流式传输 HTML},onError(err) {console.error(err);res.status(500).send('Internal Server Error');}});
}
  • renderToPipeableStream 替代了 renderToString,支持逐步发送 HTML
  • onShellReady 事件触发时,就可以开始向客户端流式发送内容。

2. 关键优化点

(1)更快的 FCP(First Contentful Paint)

  • 静态内容可以立即渲染,减少白屏时间。
  • 服务器端可优先返回非阻塞组件,提高用户体验。

(2)Suspense 支持流式 SSR

  • React 18 允许在 SSR 中使用 <Suspense>,未加载的数据部分可以稍后填充,不会影响整个页面的渲染。

示例:

import { Suspense } from 'react';function SlowComponent() {const data = fetchData(); // 假设这里是一个耗时请求return <div>{data}</div>;
}export default function App() {return (<div><h1>My App</h1><Suspense fallback={<p>Loading...</p>}><SlowComponent /></Suspense></div>);
}

在 React 18 SSR:

  1. 服务器会先返回 <h1>My App</h1><p>Loading...</p>
  2. SlowComponent 数据加载完,再填充真实内容。

3. 流式 SSR vs. 传统 SSR vs. CSR

方式传统 SSR流式 SSRCSR(客户端渲染)
页面渲染时机数据加载完成后一次性返回逐步返回,先渲染可用部分HTML 先返回,JS 再渲染
性能可能导致服务器阻塞更快响应用户,减少白屏依赖 JS 解析,SEO 不佳
SEO 友好
适用场景适用于小型 SSR 项目适用于高并发、内容较多的 SSR 项目适用于动态交互强的 SPA

4. 总结

流式 SSR 允许服务器逐步发送 HTML,提升页面加载速度。
支持 <Suspense> 进行流式渲染,未加载的数据不会阻塞整个页面。
减少 TTFB(首字节时间) ,提高用户体验。
适用于高并发和需要快速响应的应用,如新闻站点、电商页面等。

React 18 的流式 SSR 使得服务端渲染更加高效,结合 Suspense 还能提供更好的用户体验,是前端优化的重要特性之一!

79.React18新特性——Server Component

React 18 的 Server Components(服务端组件) 是 React 生态中的一项革新,旨在通过服务端与客户端的协同渲染,优化性能并提升开发体验。以下是其核心要点与面试回答方向:


一、核心概念

  • 服务端专属:Server Components 仅在服务器端运行,不参与客户端交互,代码不会发送到浏览器,减少客户端包体积
  • 动态与静态结合:允许在服务端动态生成组件树,并与客户端组件(Client Components)无缝集成,形成混合渲染模式。
  • 直接访问后端资源:可直接连接数据库、读取文件或调用内部 API,避免客户端到服务端的额外请求

二、核心特性

1. 减少客户端代码
  • 零客户端代码:Server Components 的代码(包括依赖)不打包到客户端,显著降低首屏加载体积。

  • 示例

    // ServerComponent.server.js (服务端组件)
    import db from 'server-db'; // 仅在服务端运行export default function ProductDetails({ id }) {const product = db.query('SELECT * FROM products WHERE id = ?', id);return <div>{product.name}</div>; // 静态内容
    }
    
2. 流式渲染(Streaming SSR)
  • 分块传输:服务端将渲染结果拆分为多个数据块,通过 HTTP 流(Stream)逐步发送到客户端,加速首屏显示

  • 结合 Suspense:与 Suspense 配合,优先渲染关键内容,延迟非关键部分。

    // 客户端组件
    import ProductDetails from './ProductDetails.server';function App() {return (<Suspense fallback={<Loading />}><ProductDetails id={1} /></Suspense>);
    }
    
3. 数据获取优化
  • 无客户端数据请求:服务端组件直接访问数据源,避免客户端通过 fetch 二次请求,减少网络延迟
  • 自动序列化:服务端组件向客户端传递的 props 会自动序列化为 JSON,支持基础类型、JSX 元素及客户端组件引用。
4. 与客户端组件协作
  • 混合渲染:通过文件后缀(如 .server.js.client.js)区分组件类型,服务端组件可嵌套客户端组件,反之不行。

    // ProductPage.server.js
    import AddToCart from './AddToCart.client'; // 导入客户端组件export default function ProductPage() {return (<div><ProductDetails id={1} /><AddToCart productId={1} /> // 交互逻辑由客户端处理</div>);
    }
    

三、与传统 SSR 的区别

特性传统 SSRServer Components
代码体积服务端生成 HTML,但客户端仍需加载完整 JS 包服务端组件代码不发送到客户端
数据获取需在客户端通过 getServerSideProps 等获取直接访问服务端资源,无额外请求
交互性需水合(Hydration)后交互需结合客户端组件处理交互
渲染粒度整页渲染按组件级动态流式渲染

四、适用场景

  1. 内容型页面:博客、文档、商品详情页等以静态内容为主的场景。
  2. 数据敏感操作:直接访问数据库或内部 API,避免暴露敏感逻辑到客户端。
  3. 性能敏感应用:需减少客户端代码体积,提升低端设备或慢网络下的体验。

五、限制与注意事项

  • 无交互能力:不能使用 useStateuseEffect 或浏览器 API(如 localStorage)。
  • 序列化约束:传递的 props 需可序列化,避免包含函数或复杂对象。
  • 框架依赖:需配合支持 Server Components 的框架(如 Next.js)或自定义服务端环境。

六、示例:混合渲染流程

  1. 服务端渲染

    • 运行 ProductPage.server.js,获取数据库数据。
    • 将静态内容序列化为 HTML,动态部分标记为占位符。
  2. 流式传输

    • 客户端逐步接收 HTML 和客户端组件代码。
    • AddToCart.client.js 被加载并水合,启用交互。
  3. 最终结果

    • 用户立即看到商品信息,按钮交互由客户端处理。

七、总结

React Server Components 通过服务端与客户端的职责分离,解决了传统 SSR 的代码冗余和数据请求问题,尤其适合内容优先的场景。其核心优势包括:

  • 更小的客户端包体积
  • 直接服务端数据访问
  • 流式渲染加速首屏

开发者需注意其限制,合理划分服务端与客户端组件,结合框架能力(如 Next.js)最大化性能收益。这一特性标志着 React 向全栈开发迈出了重要一步。

80.React18新特性——OffScreen

大白话:支持保持组件的状态,而删除组件的UI 部分,很方面的实现与渲染,或者keep-alive

React 18 的 Offscreen(或实验性 API unstable_Offscreen)是一个旨在优化渲染性能的特性,主要用于管理不可见组件的渲染行为,减少不必要的计算和 DOM 操作。以下是其核心要点与回答方向:


一、核心目标

  • 保留组件状态与 DOM:当组件暂时不可见时(如标签页切换、弹窗关闭),保持其 DOM 结构和状态,避免重复挂载/卸载带来的性能损耗。
  • 后台预渲染:结合并发模式,在后台静默渲染隐藏的组件,为后续显示提前准备。
  • 资源优化:暂停不可见组件的副作用(如动画、数据订阅),减少 CPU 和内存占用。

二、核心特性

1. 状态保留与快速恢复
  • 避免重新挂载:组件隐藏时保留其状态(如滚动位置、表单输入),再次显示时无需重新初始化。

  • 示例

    import { unstable_Offscreen as Offscreen } from 'react';function App() {const [show, setShow] = useState(true);return (<div><button onClick={() => setShow(!show)}>Toggle</button><Offscreen mode={show ? "visible" : "hidden"}><ExpensiveComponent /> // 隐藏时保留 DOM 和状态</Offscreen></div>);
    }
    
2. 与并发模式协同
  • 后台渲染:在组件隐藏期间,React 可异步完成其未完成的渲染任务(如数据加载),待显示时直接提交结果。
  • 优先级控制:隐藏组件的更新被标记为低优先级,避免阻塞用户交互。
3. 副作用管理
  • 自动暂停/恢复:隐藏时暂停 useEffect、动画等副作用,显示时自动恢复。
  • 资源释放:若组件长期隐藏,可选择彻底卸载以释放资源(需开发者配置)。

三、与传统处理方式的对比

场景传统方式Offscreen
组件隐藏卸载组件,丢失状态保留 DOM 和状态,快速恢复
复杂组件渲染每次显示需重新渲染,可能卡顿后台预渲染,显示时无延迟
副作用管理需手动取消订阅或清理自动暂停/恢复,减少内存泄漏风险

四、适用场景

  1. 标签页/路由切换:保留非活动标签页的状态,提升切换流畅度。
  2. 弹窗/抽屉组件:避免重复渲染弹窗内容,快速响应用户操作。
  3. 虚拟列表优化:对屏幕外列表项使用 Offscreen,减少渲染压力。

五、实现原理

  • DOM 隐藏而非卸载:通过 CSS display: nonevisibility: hidden 隐藏组件,保持 DOM 树结构。
  • Fiber 节点标记:在协调阶段跳过隐藏组件的更新检查,除非强制刷新。
  • 副作用调度:通过 React 调度器暂停隐藏组件的副作用执行。

六、注意事项

  • 实验性 API:截至 React 18.2,unstable_Offscreen 仍为实验性功能,API 可能变更。
  • 内存占用:长期保留大量隐藏组件可能增加内存消耗,需权衡使用。
  • 兼容性:需配合 Concurrent Mode 使用,传统同步渲染不生效。

七、示例:路由切换优化

import { unstable_Offscreen as Offscreen } from 'react';
import { Routes, Route, useLocation } from 'react-router-dom';function App() {const location = useLocation();return (<Routes location={location}><Route path="/" element={<Home />} /><Route path="/dashboard" element={<Offscreen mode="visible"><Dashboard /> // 显示时优先渲染</Offscreen>} /><Route path="/settings" element={<Offscreen mode="hidden"><Settings /> // 隐藏时保留状态</Offscreen>} /></Routes>);
}

总结

React 18 的 Offscreen 特性通过智能管理不可见组件的生命周期,显著提升了复杂应用的渲染效率与用户体验。其核心价值在于:

  • 状态保留:避免重复初始化带来的性能损耗。
  • 后台渲染:利用空闲资源预计算,减少用户等待时间。
  • 副作用控制:自动化资源管理,降低开发复杂度。

尽管目前仍处于实验阶段,Offscreen 展现了 React 在性能优化方向的持续探索,值得开发者关注其未来正式发布后的应用场景。

81.React18新特性——卸载组件时的更新状态警告

React 18 新特性 —— 卸载组件时的更新状态警告(Updating a component while unmounting)

在 React 18 之前,如果组件在卸载(unmount)时仍然尝试更新状态(setStateuseState),React 会抛出**“Can’t perform a React state update on an unmounted component”** 警告。这通常是由于异步操作(如 fetchsetTimeoutuseEffect 副作用)未在组件卸载时正确清理导致的。


React 18 的改进

在 React 18 之后,React 变得更聪明了

  1. 自动检测并忽略卸载组件的更新,不会再抛出警告。
  2. 提高应用稳定性,避免无效的状态更新影响其他组件。

🔹 示例:React 18 之前

function Example() {const [data, setData] = useState(null);useEffect(() => {fetch('/api/data').then(res => res.json()).then(result => setData(result));// 🚨 组件卸载时,没有清理请求,可能导致警告}, []);return <div>{data}</div>;
}

如果用户在数据请求完成之前离开当前页面卸载组件,组件仍然尝试 setData(result),这会触发 React 17 及之前版本的状态更新警告

🔹 React 18 之后

function Example() {const [data, setData] = useState(null);useEffect(() => {let isMounted = true;fetch('/api/data').then(res => res.json()).then(result => {if (isMounted) setData(result); // ✅ React 18 处理得更好});return () => {isMounted = false; // 🔹 组件卸载时标记};}, []);return <div>{data}</div>;
}

在 React 18,即使不手动清理副作用,React 也会自动忽略组件卸载后的更新,从而避免警告。


为什么要优化这个问题?

  • 避免开发者手动清理副作用(比如 isMounted 变量)。
  • 解决了异步更新导致的潜在 Bug
  • 提升应用稳定性,避免不必要的错误提示。

总结

React 18 自动忽略卸载组件的更新,避免不必要的警告
减少开发者手动处理的负担,代码更简洁
增强应用稳定性,避免潜在的内存泄漏和状态错误

虽然 React 18 进行了优化,但良好的副作用清理习惯仍然是最佳实践,比如在 useEffectreturn 语句中清理定时器、取消请求等。

82.什么是服务端渲染什么是客户端渲染

服务端渲染(SSR) vs. 客户端渲染(CSR)

在 Web 开发中,页面的渲染方式主要有两种:

  • 服务端渲染(SSR - Server-Side Rendering)
  • 客户端渲染(CSR - Client-Side Rendering)

它们的区别在于HTML 生成的时机

  • SSR:HTML 在服务器端生成,然后返回完整的页面给浏览器。
  • CSR:HTML 在客户端(浏览器)生成,服务器只返回 JavaScript 代码,由浏览器执行后动态渲染页面。

1. 什么是服务端渲染(SSR)?

概念

服务端渲染(SSR)是指服务器在接收到请求后,直接返回完整的 HTML 页面
浏览器接收到 HTML 后,可以立即渲染页面,无需等待 JavaScript 加载和执行。

工作流程

  1. 浏览器发送请求给服务器(如 example.com)。
  2. 服务器执行 React/Vue/Next.js 代码,渲染出完整的 HTML 页面。
  3. 返回完整 HTML 页面给浏览器,用户可以立刻看到页面内容
  4. 客户端加载 JavaScript,让页面变得可交互(称为水合(Hydration) )。

示例(React SSR)

import express from 'express';
import { renderToString } from 'react-dom/server';
import App from './App';const app = express();app.get('*', (req, res) => {const html = renderToString(<App />);res.send(`<!DOCTYPE html><html><body>${html}</body></html>`);
});app.listen(3000, () => console.log('Server is running on port 3000'));

这里 renderToString() 会在服务器端生成 HTML 并返回给浏览器。


SSR 的优点

SEO 友好:搜索引擎可以直接解析 HTML,提高排名。
首屏加载快:页面内容在服务器上渲染好后直接返回,减少白屏时间。
适合内容型网站(如博客、新闻站点、电商网站)。

SSR 的缺点

服务器压力大:每个请求都需要服务器计算,可能影响并发性能。
交互需要水合(Hydration) :页面渲染后,仍需 JavaScript 绑定事件,使页面可交互。


2. 什么是客户端渲染(CSR)?

概念

客户端渲染(CSR)是指服务器只返回一个基本的 HTML 结构,页面内容由 JavaScript 在浏览器中动态渲染

工作流程

  1. 服务器返回一个基本 HTML(通常只包含一个 div#root)。
  2. 浏览器下载 JavaScript,并在浏览器中执行 React/Vue 代码。
  3. 前端框架(如 React、Vue)动态渲染页面
  4. 用户可以看到页面内容并进行交互

示例(React CSR)

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';const root = document.getElementById('root');
ReactDOM.createRoot(root).render(<App />);

这里 ReactDOM.createRoot().render() 会在浏览器端动态生成页面内容。


CSR 的优点

前后端分离,适合 SPA(单页面应用)
用户交互体验更流畅(页面切换更快)。
服务器压力小,因为页面渲染由客户端完成。

CSR 的缺点

首屏加载慢,需要先下载 JavaScript,再渲染页面。
SEO 不友好(搜索引擎爬取的是空 HTML)。
依赖 JavaScript,如果禁用 JavaScript,页面可能无法正常加载。


3. SSR vs. CSR 对比

特性SSR(服务端渲染)CSR(客户端渲染)
首屏渲染速度快(服务器返回完整 HTML)慢(等待 JS 解析并渲染)
SEO 友好好(搜索引擎可直接爬取 HTML)差(搜索引擎可能爬不到内容)
服务器压力高(每次请求都要计算)低(服务器只提供 API 数据)
用户交互体验需要 Hydration,使页面可交互交互流畅
适用场景适用于 SEO 重要的网站,如博客、新闻、电商适用于交互性强的应用,如管理后台、社交平台

4. SSR 和 CSR 的结合

方案 1:同构渲染(Universal Rendering)

  • 服务器先进行 SSR,返回 HTML 让用户立即看到内容。
  • 然后客户端进行 Hydration,绑定事件,使页面可交互。

示例(Next.js 实现同构渲染):

export async function getServerSideProps() {const data = await fetchData(); // 在服务器端获取数据return { props: { data } };
}export default function Page({ data }) {return <div>{data}</div>;
}

方案 2:静态生成 + CSR(Next.js SSG + CSR)

  • 静态页面(SSG) :提前在构建时生成 HTML,提高性能。
  • 交互部分(CSR) :通过 React 加载数据,使页面可交互。

示例(Next.js SSG + CSR):

export async function getStaticProps() {const data = await fetchData();return { props: { data } };
}export default function Page({ data }) {return <div>{data}</div>;
}

5. 总结

服务端渲染(SSR)客户端渲染(CSR)
渲染位置服务器浏览器
首屏速度快(HTML 直接返回)慢(需要下载 JS 并执行)
SEO 友好✅ 是❌ 不是
服务器压力
适用场景适合 SEO 需求,如博客、电商、新闻适合交互复杂的 SPA,如后台管理系统

什么时候用 SSR?

  • SEO 需求高(博客、新闻、电商等)。
  • 需要更快的首屏加载

什么时候用 CSR?

  • 交互复杂的应用(如管理后台、社交平台)。
  • 用户多次切换页面(如 SPA)。

最佳方案:结合 SSR 和 CSR

  • Next.jsNuxt.js 等框架支持同构渲染,结合 SSR 和 CSR 的优势。
  • 静态生成(SSG) + CSR 是性能最优解。

React 18 进一步优化了 SSR,引入了流式 SSR(Streaming SSR) ,提升了 SSR 的性能,使其更适用于大规模应用。

83.React18新特性——Strict Mode

React 18 中的 Strict Mode 是一个开发环境下的工具,旨在帮助开发者提前发现潜在问题,尤其是为 并发渲染(Concurrent Rendering) 和未来 React 特性铺平道路。以下是其核心特性和作用的详细解析:


一、Strict Mode 的核心作用

  1. 检测不安全的副作用

    • 重复调用 Effects:在开发模式下,React 会故意多次挂载和卸载组件,导致 useEffectuseLayoutEffect 的清理函数与执行函数被调用两次。
    • 目的:暴露未正确清理的副作用(如未取消订阅事件、未关闭网络请求),确保组件能安全应对并发渲染下的多次渲染。
  2. 识别废弃的 API 和模式

    • 警告使用过时的 API(如 findDOMNode、旧版 context API)。
    • 检测不安全的生命周期方法(如 UNSAFE_componentWillMount)。
  3. 验证并发模式兼容性

    • 模拟并发渲染的极端场景(如渲染中断、任务优先级变化),提前暴露竞态条件(Race Conditions)或状态同步问题。

二、React 18 中 Strict Mode 的新行为

1. 组件双重渲染(Double Invocation)
  • 现象:在开发模式下,组件的函数体、useState 初始化、useEffect 等会被连续调用两次

  • 示例

    function MyComponent() {console.log("Render"); // 输出两次useEffect(() => {console.log("Effect"); // 输出两次,且 cleanup 在两次之间执行return () => console.log("Cleanup");}, []);return <div>Test</div>;
    }
    
  • 目的:确保副作用逻辑的幂等性(Idempotent),即多次执行不会产生错误。

2. 模拟卸载后重新挂载
  • 行为:组件首次挂载后立即卸载,再重新挂载。

  • 验证点

    • 组件是否能正确处理瞬时挂载(如快速导航导致的组件频繁加载/卸载)。
    • 资源(如定时器、订阅)是否在 useEffect 的 cleanup 函数中被正确释放。
3. 并发渲染压力测试
  • 行为:在并发模式下,React 可能中断渲染过程以处理更高优先级任务,Strict Mode 会模拟此类场景。

  • 验证点

    • 组件状态更新是否具备一致性(如避免部分状态更新导致 UI 撕裂)。
    • 副作用逻辑是否对渲染中断具备容错性。

三、Strict Mode 解决的问题

  1. 副作用管理

    • 避免因未清理的副作用导致内存泄漏或数据不一致。
  2. 并发模式兼容性

    • 确保组件在渲染可中断、任务批处理等并发特性下表现稳定。
  3. 代码质量提升

    • 强制开发者遵循 React 最佳实践,减少技术债务。

四、如何适配 Strict Mode

  1. 副作用幂等化

    • 确保 useEffect 中的逻辑可重复执行而不出错(如通过唯一标识符避免重复请求)。
  2. 正确清理资源

    • useEffect 的 cleanup 函数中释放所有资源(如取消订阅、关闭连接)。
  3. 避免依赖渲染次数

    • 不假设组件只渲染一次(如避免在渲染函数中直接修改外部状态)。

五、示例:修复双重渲染问题

问题代码

let initialized = false;function MyComponent() {useEffect(() => {if (!initialized) {initialized = true; // 依赖外部变量,导致多次执行异常fetchData();}}, []);// ...
}

修复方案

function MyComponent() {useEffect(() => {const controller = new AbortController();fetchData({ signal: controller.signal });return () => controller.abort(); // 正确清理}, []);// ...
}

六、总结

React 18 的 Strict Mode 通过模拟极端场景(如双重渲染、并发中断),强制开发者编写更健壮的代码,为并发渲染和未来特性提供兼容性保障。其核心价值在于:

  • 提前暴露问题:在开发阶段发现并发模式下的潜在缺陷。
  • 推动最佳实践:引导开发者遵循 React 的副作用管理和状态更新规范。

84.React18新特性——Suspense 不再需要 fallback

在 React 18 中,Suspense 不再强制要求提供 fallback 属性,这一变化是为了提升开发灵活性并更好地支持并发渲染(Concurrent Rendering)嵌套 Suspense 边界的场景。以下是其核心原理和影响的详细解析:


一、行为变化:从强制到可选

1. React 17 及之前
  • 强制要求:每个 <Suspense> 必须提供 fallback 属性,否则会抛出警告或错误。

  • 示例

    // React 17:必须提供 fallback
    <Suspense fallback={<Loading />}><AsyncComponent />
    </Suspense>
    
2. React 18 的改进
  • fallback 变为可选:可以省略 fallback,此时若子组件处于挂起状态,React 会向上查找最近的父级 Suspense 边界并使用其 fallback

  • 示例

    // React 18:允许省略 fallback
    <Suspense>  {/* 无 fallback */}<AsyncComponent />
    </Suspense>
    

二、设计动机

1. 支持嵌套 Suspense 边界
  • 场景:在复杂组件树中,可能存在多层 Suspense 嵌套(如全局加载层 + 局部加载层)。
  • 问题:强制每个 Suspense 提供 fallback 会导致冗余代码(如重复的加载动画)。
  • 解决方案:子级 Suspense 可省略 fallback,直接继承父级的加载状态,实现状态冒泡
2. 适配并发渲染
  • 并发特性:在并发模式下,React 可以中断渲染并优先处理高优先级更新。
  • 行为变化:若子组件挂起且无 fallback,React 会保持当前 UI 不变,直到异步操作完成,避免频繁切换加载状态(如闪烁)。
3. 简化代码
  • 减少冗余:对于无需独立加载状态的场景(如静默加载),省略 fallback 使代码更简洁。

三、具体行为与规则

1. fallback 时的挂起行为
  • 向上冒泡:子组件挂起时,React 会向父级 Suspense 边界传递挂起状态,直到找到有 fallback 的祖先。
  • 无父级 Suspense:若整个组件树均无 fallback,React 会抛出错误(需至少一个 Suspense 提供 fallback)。
2. 与过渡(Transitions)结合
  • 示例:使用 useTransition 标记非紧急更新,即使子 Suspense 无 fallback,也能避免界面突然切换。
const [isPending, startTransition] = useTransition();
startTransition(() => {// 触发异步更新
});
return (<div>{isPending && <GlobalLoading />}<Suspense>  {/* 无 fallback */}<AsyncComponent /></Suspense></div>
);

四、使用场景与最佳实践

1. 场景 1:嵌套 Suspense 的全局加载
// 外层:全局加载层
<Suspense fallback={<AppLoading />}><Layout>{/* 内层:局部组件无需独立加载状态 */}<Suspense>  {/* 无 fallback */}<UserProfile /></Suspense></Layout>
</Suspense>
2. 场景 2:静默加载(无视觉反馈)
// 组件挂起时不显示任何加载状态,直到数据就绪
<Suspense>  {/* 无 fallback */}<CommentsSection />  // 静默加载评论
</Suspense>
3. 场景 3:服务端流式渲染(SSR)
  • 行为:在流式 SSR 中,未就绪的 Suspense 区块可先发送 HTML 片段,后续补充内容,无需强制 fallback

五、注意事项

  1. 至少一个 Suspense 需有 fallback:整个组件树中必须存在至少一个 Suspense 提供 fallback,否则会报错。
  2. 避免无限挂起:若异步操作永远不完成且无 fallback,界面可能卡死,需结合错误边界(Error Boundaries)处理异常。

六、总结

React 18 中 Suspense 不再强制要求 fallback,这一改进使得:

  • 嵌套 Suspense 更灵活:子边界可冒泡到父级加载状态,减少冗余代码。
  • 并发渲染更友好:支持静默加载和优先级调度,提升用户体验。
  • 代码更简洁:简化无需独立加载状态的场景。

开发者需根据场景选择是否省略 fallback,并确保组件树中至少有一个 Suspense 提供回退 UI,以兼容异步渲染流程。

85.React——super()和super(props)有什么区别

在 React 类组件中,super()super(props) 的区别在于构造函数中是否能够访问 this.props,具体分析如下:


一、核心区别

调用方式super()super(props)
参数传递不传递 props 给父类构造函数传递 props 给父类构造函数
this.props 访问时机构造函数内 this.propsundefined构造函数内可直接访问 this.props
使用场景构造函数中不需要 props构造函数中需要依赖 props

二、详细解释

1. super(props) 的作用
  • 传递 props 到父类React.Component 的构造函数需要接收 props 参数,调用 super(props) 会将 props 传递给父类,完成初始化。

  • 构造函数内访问 this.props:只有调用 super(props) 后,才能在构造函数中直接使用 this.props

    class MyComponent extends React.Component {constructor(props) {super(props); // 传递 propsconsole.log(this.props); // 正确输出 props}
    }
    
2. super() 的局限性
  • 不传递 props:若省略 props 参数,父类构造函数无法初始化 this.props

  • 构造函数内 this.propsundefined

    class MyComponent extends React.Component {constructor(props) {super(); // 未传递 propsconsole.log(this.props); // undefined}
    }
    
  • 其他生命周期方法不受影响:即使不传递 props,在 render()componentDidMount() 等方法中,this.props 仍可正常访问(React 会在构造函数执行后自动注入 props)。


三、为什么需要关注这一点?

1. 初始化状态依赖 props

若组件的初始状态(this.state)需要基于 props 计算,则必须通过 super(props) 确保 this.props 可用:

class MyComponent extends React.Component {constructor(props) {super(props);this.state = { value: props.initialValue }; // 需要访问 props}
}
2. 历史代码兼容性

在 React 17 之前,context 的传递也依赖 super(props)。若未传递 propsthis.context 在构造函数中可能异常(React 17+ 已修复此问题)。


四、最佳实践

  1. 始终传递 super(props)

    • 即使构造函数中暂时不需要 props,显式传递可避免未来扩展时遗漏。
    • 保持代码一致性,减少潜在错误。
  2. 无构造函数时无需处理

    • 若未定义构造函数,React 会自动调用 super(props)
    class MyComponent extends React.Component {// 无构造函数,自动调用 super(props)render() {return <div>{this.props.text}</div>;}
    }
    

五、总结

  • super(props) :确保构造函数内可访问 this.props,适用于需要基于 props 初始化状态或执行其他操作的场景。
  • super() :省略 props 传递,构造函数内 this.props 不可用,但其他生命周期方法不受影响。
  • 推荐做法:统一使用 super(props),避免因遗漏导致的隐蔽问题。

86.React面试题——说说对React中类组件和函数组组件的理解?有什么

在 React 中,组件是构建 UI 的基本单元,主要分为 类组件(Class Components)函数组件(Function Components) 。两者在 React 16.8 之前存在较大区别,但随着 Hooks 的引入,函数组件的能力得到了增强,逐渐成为主流。


1. 类组件(Class Component)

定义
类组件是基于 ES6 class 语法的组件,需要继承 React.ComponentReact.PureComponent,并实现 render 方法返回 JSX。

特点

  • 有自己的 state 和生命周期方法(如 componentDidMountshouldComponentUpdate 等)。
  • 需要手动绑定 this(如事件处理函数)。
  • 支持 ref 直接访问 DOM

示例

class ClassComponent extends React.Component {constructor(props) {super(props);this.state = { count: 0 };}handleClick = () => {this.setState({ count: this.state.count + 1 });};render() {return (<div><p>Count: {this.state.count}</p><button onClick={this.handleClick}>Increment</button></div>);}
}

2. 函数组件(Function Component)

定义: 函数组件是基于普通 JavaScript 函数的组件,接收 props 作为参数,并返回 JSX 结构。

特点

  • 没有 this,更加简洁
  • 通过 useStateuseEffect 等 Hooks 处理状态和生命周期
  • 更符合函数式编程思想,易于复用和测试。

示例

import { useState } from "react";const FunctionComponent = () => {const [count, setCount] = useState(0);return (<div><p>Count: {count}</p><button onClick={() => setCount(count + 1)}>Increment</button></div>);
};

3. 类组件 vs 函数组件

比较项类组件 (Class Component)函数组件 (Function Component)
语法风格需要 class 继承 React.Component直接定义为普通函数
状态管理通过 this.statethis.setState通过 useState Hook
生命周期componentDidMountcomponentDidUpdatecomponentWillUnmountuseEffect 代替生命周期
this 绑定需要手动绑定 this没有 this,避免绑定问题
代码复用通过 HOC(高阶组件)、Render Props通过 Hooks 使代码更清晰
性能优化需要 shouldComponentUpdatePureComponentReact.memouseCallback 进行优化
可读性代码较冗长,复杂度较高更简洁,易读易维护

4. 为什么函数组件逐渐替代类组件?

  1. 代码更简洁:不用管理 this,不需要冗长的生命周期方法。
  2. 性能优化:函数组件默认不会创建实例,减少内存占用,结合 React 18 并发模式,渲染更流畅。
  3. Hooks 让函数组件更强大useStateuseEffectuseReducer 等让函数组件可以处理复杂逻辑。
  4. 未来趋势:React 官方推荐使用函数组件,社区库也都优先支持 Hooks。

5. 什么时候仍然使用类组件?

尽管函数组件已经成为主流,但某些情况下仍可能使用类组件:

  • 需要使用 componentDidCatch 进行错误边界处理(但 React 18 引入 useErrorBoundary)。
  • 维护老项目时,已有大量类组件,不便于重构。

6. 总结

  • React 早期主要使用类组件,但 Hooks 引入后,函数组件成为主流。
  • 类组件有 state 和生命周期方法,适用于旧版本 React 项目。
  • 函数组件结合 Hooks,更加简洁、高效,并且是未来趋势。
  • 除非有特殊需求(如错误边界),否则应优先使用函数组件。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/27932.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

突破光学成像局限:全视野光学血管造影技术新进展

全视野光学血管造影&#xff08;FFOA&#xff09;作为一种实时、无创的成像技术&#xff0c;能够提取生物血液微循环信息&#xff0c;为深入探究生物组织的功能和病理变化提供关键数据。然而&#xff0c;传统FFOA成像方法受到光学镜头景深&#xff08;DOF&#xff09;的限制&am…

Deepgram推出Nova-3 Medical,AI语音转录助力医疗行业

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

centOS 环境 安装redis方法

一、准备centOS环境 参考文章&#xff1a;Hyper-V 安装CentOS7_代码草率了的博客-CSDN博客 二、redis官网 地址&#xff1a;Download | Redis 演示版本为?redis-5.0.14.tar.gz 三、redis源码编译 登录后创建soft目录 进入目录使用wget下载所需资源包 命令&#xff1a;w…

[51 单片机] --串口编程

1&#xff0c;通讯方式基本概念 1&#xff0c;按照 --> 数据传送方式串行通讯&#xff1a;使用一条数据线&#xff0c;将数据一位一位地依次传输&#xff0c;每一位数据占据一个固定的时间长度&#xff0c;串行通信的特点&#xff1a;传输线少&#xff0c;长距离传送时成本…

Golang的微服务服务发现机制

## 1. Golang微服务服务发现机制 微服务架构已经成为当今软件开发的主流趋势&#xff0c;它能将复杂的单体应用拆分成小而独立的服务单元&#xff0c;实现更快的开发、部署和扩展。在微服务架构中&#xff0c;服务发现是非常重要的一环&#xff0c;它能够实现服务之间的自动发现…

Python 创建地形图

原始地 DEM。 火山口湖 (OR) 区域的起始 DEM。数据来自 NASA DEM 本身非常美丽&#xff0c;但我们先进行分层。 将自定义色彩图应用于 DEM 对于我在 ArcGIS Pro 版本中所做的初始高程样式着色&#xff0c;我使用了“高程 #7”。在 matplotlib 中可用的标准颜色图中&#xff…

《Operating System Concepts》阅读笔记:p180-p187

《Operating System Concepts》学习第 20 天&#xff0c;p180-p187 总结&#xff0c;总计 8 页。 一、技术总结 1.forke-join A strategy for thread creation in which the main parent thread creates (forks) one or more child threads and then waits for the children…

文心4.5,大模型下半场的野心之作

2025年开年&#xff0c;全球大模型竞赛进入白热化阶段。2月28日&#xff0c;百度宣布其文心大模型4.5将于3月16日正式上线&#xff0c;强调其原生多模态与深度思考能力&#xff0c;并计划于6月30日开源。这一动作不仅标志着百度技术路线的重大转向&#xff0c;更被视为中国大模…

transformer架构解析{前馈全连接层,规范化层,子层(残差)连接结构}(含代码)-4

目录 前言 前馈全连接层 学习目标 什么是前馈全连接层 前馈全连接层的作用 前馈全连接层代码实现 规范化层 学习目标 规范化层的作用 规范化层的代码实现 子层&#xff08;残差&#xff09;连接结构 学习目标 什么是子层&#xff08;残差&#xff09;连接结构 子层连…

Django视图与URLs路由详解

在Django Web框架中&#xff0c;视图&#xff08;Views&#xff09;和URLs路由&#xff08;URL routing&#xff09;是Web应用开发的核心概念。它们共同负责将用户的请求映射到相应的Python函数&#xff0c;并返回适当的响应。本篇博客将深入探讨Django的视图和URLs路由系统&am…

串口通讯基础

第1章 串口的发送和接收过程 1.1 串口接收过程 当上位机给串口发送(0x55)数据时&#xff0c;MCU的RX引脚接受到&#xff08;0x55&#xff09;数据&#xff0c;数据(0x55)首先进入移位寄存器。数据全部进入移位寄存器后&#xff0c;一次将&#xff08;0x55&#xff09;全部搬运…

kakfa-3:ISR机制、HWLEO、生产者、消费者、核心参数负载均衡

1. kafka内核原理 1.1 ISR机制 光是依靠多副本机制能保证Kafka的高可用性&#xff0c;但是能保证数据不丢失吗&#xff1f;不行&#xff0c;因为如果leader宕机&#xff0c;但是leader的数据还没同步到follower上去&#xff0c;此时即使选举了follower作为新的leader&#xff…

基于Linux系统的物联网智能终端

背景 产品研发和项目研发有什么区别&#xff1f;一个令人发指的问题&#xff0c;刚开始工作时项目开发居多&#xff0c;认为项目开发和产品开发区别不大&#xff0c;待后来随着自身能力的提升&#xff0c;逐步感到要开发一个好产品还是比较难的&#xff0c;我认为项目开发的目的…

STM32——DMA详解

目录 一&#xff1a;DMA简介 二&#xff1a;DMA基本结构 三&#xff1a;DMA实现过程 1.框图 2.DMA进行转运的条件 四&#xff1a;函数 一&#xff1a;DMA简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设存储器或者存储器和存储器之间的高速数据传输&…

告别卡顿,拥抱流畅!MemReduct——内存清理工具

先给安装包下载地址&#xff1a;MemReduct.exe下载&#xff0c;无脑下一步安装即可。 MemReduct 是一款出色的内存清理工具&#xff0c;以下是对它的详细介绍&#xff1a; 功能特点 高效内存清理&#xff1a;采用先进算法及系统底层 API&#xff0c;能智能清理系统缓存、应用…

告别GitHub连不上!一分钟快速访问方案

一、当GitHub抽风时&#xff0c;你是否也这样崩溃过&#xff1f; &#x1f621; npm install卡在node-sass半小时不动&#x1f62d; git clone到90%突然fatal: early EOF&#x1f92c; 改了半天hosts文件&#xff0c;第二天又失效了... 根本原因&#xff1a;传统代理需要复杂…

指纹细节提取(Matlab实现)

指纹细节提取概述指纹作为人体生物特征识别领域中应用最为广泛的特征之一&#xff0c;具有独特性、稳定性和便利性。指纹细节特征对于指纹识别的准确性和可靠性起着关键作用。指纹细节提取&#xff0c;即从指纹图像中精确地提取出能够表征指纹唯一性的关键特征点&#xff0c;是…

【对话推荐系统综述】A Survey on Conversational Recommender Systems

文章信息&#xff1a; 发表于&#xff1a;ACM Computing Surveys 2021 原文链接&#xff1a;https://arxiv.org/abs/2004.00646 Abstract 推荐系统是一类软件应用程序&#xff0c;旨在帮助用户在信息过载的情况下找到感兴趣的项目。当前的研究通常假设一种一次性交互范式&am…

【0001】初识Java

Java是世界上最好的语言&#xff0c;没有之一&#xff01;&#xff01;&#xff01; Java是世界上最好的语言&#xff0c;没有之一&#xff01;&#xff01;&#xff01; Java是世界上最好的语言&#xff0c;没有之一&#xff01;&#xff01;&#xff01; 重要的事情说三遍&am…

全向广播扬声器在油气田中的关键应用 全方位守护安全

油气田作为高风险作业场所&#xff0c;安全生产始终是重中之重。在紧急情况下&#xff0c;如何快速、有效地传达信息&#xff0c;确保人员安全撤离&#xff0c;是油气田安全管理的关键环节。全向广播扬声器凭借其全方位覆盖、高音质输出和强大的环境适应性&#xff0c;成为油气…