前端面试准备指南四之React篇


一、React Key的作用

1.1 Key的定义

Keys 是 React 用于追踪哪些列表中元素被修改、被添加或者被移除的辅助标识。

1.2 Key的作用

  • 帮助 React 识别哪些元素发生了变化
  • 提高 diff 算法的效率
  • 避免不必要的重新渲染

1.3 有Key与没Key的区别

情况 有Key 没Key
列表更新 精确定位变化的元素 可能导致错误的重新渲染
元素复用 根据Key匹配原有元素 无法匹配,可能创建新元素
性能 更高 可能性能下降

1.4 同一层级节点比较

React 的 diff 算法只在同一层级的节点之间进行比较:

  • 相同Key:认为是同一个节点,比较属性变化
  • 不同Key:认为是新节点,执行插入/删除操作
  • 跨层级:无法移动,只能删除旧节点、创建新节点

1.5 最佳实践

  • 使用稳定的唯一ID作为Key
  • 避免使用数组下标作为Key(会导致渲染错误)
  • 避免使用随机数作为Key

二、虚拟DOM与Diff算法

2.1 虚拟DOM定义

虚拟DOM 本质上是 JavaScript 对象,是对 真实DOM 的抽象表现。

const vdom = {
    type: "div",
    props: { className: "container", children: "Hello" },
};

2.2 虚拟DOM优势

  • 减少直接操作DOM,提高性能
  • 跨平台能力更强(SSR、Native等)
  • 批量更新,减少重排重绘

2.3 Diff算法流程

  1. 状态变更:记录新树和旧树的差异
  2. 对比差异:通过diff算法找出最小更新点
  3. 批量更新:将差异更新到真正的DOM中

2.4 render函数原理

  1. 根据 tagName 生成父标签,读取 props,设置属性
  2. 如果有 content,设置 innerHTMLinnerText
  3. 如果存在子元素,遍历子元素递归调用 render 方法
  4. 将生成的子元素依次添加到父元素中,返回根元素

2.5 Diff算法优化策略

  • 同级比较:只比较同层级的节点
  • 类型比较:不同类型节点直接替换
  • Key匹配:通过Key精确匹配节点

三、组件通信方式

3.1 父子组件通信

父->子通信

  • 使用 props 传递数据
;

function ChildComponent(props) {
    return 
{props.name}
; }

子->父通信

  • 使用回调函数传递数据
function Parent() {
    const handleData = data => console.log(data);
    return ;
}

function Child({ onData }) {
    return ;
}

父调用子方法

  • 使用 ref 获取子组件实例
const childRef = useRef();
childRef.current.handleMethod();

3.2 兄弟组件通信

通过父组件中转

  • 状态提升到父组件,子组件通过props和回调通信

使用状态管理库

  • Redux、MobX、Zustand 等

发布订阅模式

  • 使用 EventEmitter 或自定义事件系统

3.3 跨级组件通信

Context API

const ThemeContext = React.createContext("light");

function App() {
    return (
        
            
        
    );
}

function ThemedButton() {
    const theme = useContext(ThemeContext);
    return ;
}

3.4 现代状态管理方案

方案 特点 适用场景
Zustand 轻量级,API简洁 中小型应用
Jotai 原子化状态管理 细粒度状态管理
Recoil Facebook开发 大型应用

3.5 组件组合

将子组件作为 childrenrender prop 传递,避免过度使用 Context:

function Card({ children }) {
    return 
{children}
; } function MouseTracker({ render }) { return
{render(mousePosition)}
; }

四、JSX解析

4.1 JSX本质

JSX 是 JavaScript 的语法扩展,React 使用它来描述 UI 结构。

4.2 编译过程

JSX 通过编译器(如 Babel)转换为 React.createElement 函数调用:

const element = 
Hello
; const element = React.createElement("div", { className: "greeting" }, "Hello");

4.3 createElement参数

React.createElement(
    type, // 元素类型
    props, // 元素属性
    children // 子元素
);

五、React生命周期

5.1 类组件生命周期

挂载阶段

钩子 说明
constructor 组件实例创建
getDerivedStateFromProps 从props派生state(静态方法)
render 渲染组件
componentDidMount 组件挂载完成

更新阶段

钩子 说明
getDerivedStateFromProps props变化时更新state
shouldComponentUpdate 决定是否重新渲染
render 重新渲染
getSnapshotBeforeUpdate 获取更新前快照
componentDidUpdate 组件更新完成

卸载阶段

钩子 说明
componentWillUnmount 组件卸载前清理

5.2 错误处理生命周期

钩子 说明
getDerivedStateFromError 捕获子组件错误(静态方法)
componentDidCatch 实例方法,记录错误信息

5.3 废弃的生命周期

  • componentWillMountcomponentWillReceivePropscomponentWillUpdate
  • React 16 标记为 UNSAFE_
  • React 18 完全移除

5.4 Hooks生命周期(函数组件)

类组件钩子 Hook
componentDidMount useEffect(() => {}, [])
componentDidUpdate useEffect(() => {}, [deps])
componentWillUnmount useEffect(() => { return () => {} }, [])
useEffect(() => {
    console.log("mounted");
    return () => console.log("cleanup");
}, []);

5.5 useLayoutEffect

  • 与 useEffect 类似,但同步执行
  • 在 DOM 更新后同步执行,用于DOM测量

六、React性能优化

6.1 渲染优化

函数组件优化

Hook 作用
React.memo 缓存组件渲染结果
useMemo 缓存计算结果
useCallback 缓存函数引用
const MemoizedComponent = React.memo(Component);

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

const memoizedCallback = useCallback(() => {
    doSomething(a, b);
}, [a, b]);

类组件优化

  • 使用 PureComponent 自动进行浅比较
  • 实现 shouldComponentUpdate 自定义比较逻辑

通用优化

  • 使用稳定的 key
  • 避免在 render 中创建新对象、新函数
  • 保持 props 和 state 扁平化
  • 使用 return null 代替 display: none

6.2 长列表优化

  • 虚拟滚动:react-windowreact-virtualized
  • 分页加载或无限滚动

6.3 图片优化

  • 懒加载图片
  • 使用适当尺寸的图片
  • 使用 WebP 格式

6.4 动画优化

  • 使用 transformopacity 实现动画
  • 使用 requestAnimationFrame 优化动画性能
  • 避免布局抖动

6.5 代码分割

const LazyComponent = React.lazy(() => import("./LazyComponent"));

function App() {
    return (
        }>
            
        
    );
}

6.6 Concurrent Mode优化

  • useTransition:标记非紧急更新
  • useDeferredValue:延迟处理非紧急状态

6.7 构建优化

  • 使用 esbuildswc 加速构建
  • 配置合理的 sourcemap
  • 压缩和混淆代码
  • 提取 CSS 到单独文件

七、this绑定

7.1 绑定方式对比

方式 写法 性能 推荐度
bind方法 this.handleClick = this.handleClick.bind(this) 每次渲染创建新函数
箭头函数 onClick={() => this.handleClick()} 每次渲染创建新函数
类属性 handleClick = () => {} 只创建一次

7.2 推荐写法

class MyComponent extends React.Component {
    handleClick = () => {
        console.log(this);
    };
}

八、React 18新特性

8.1 并发特性

特性 说明
时间切片 将渲染拆分为小任务,优先处理用户交互
Suspense 支持组件级别代码分割和数据获取
useTransition 标记非紧急更新
useDeferredValue 延迟处理非紧急状态

8.2 自动批处理

  • 所有状态更新都会被批处理
  • 包括 setTimeout、Promise 回调中的更新

8.3 新根API

import { createRoot } from "react-dom/client";
const root = createRoot(document.getElementById("root"));
root.render();

8.4 服务端组件

  • 服务端渲染组件,减少客户端包体积
  • 支持直接访问后端数据

8.5 其他改进

Hook 说明
useId 生成唯一ID
useSyncExternalStore 订阅外部状态
useInsertionEffect CSS-in-JS优化

8.6 现代渲染策略

策略 说明
Streaming SSR 流式服务端渲染,逐步发送HTML,减少首屏时间
SSG 静态站点生成,构建时预渲染页面
ISR 增量静态再生,运行时按需重新生成页面

九、React Fiber

9.1 Fiber架构目的

React Fiber 是 React 16 引入的新的调和算法,解决同步渲染阻塞问题。

9.2 核心特性

特性 说明
增量渲染 将渲染拆分为小单元
优先级调度 根据任务优先级安排执行顺序
可中断 允许处理更高优先级任务
时间切片 空闲时间执行渲染任务

9.3 Fiber工作流程

  1. Render阶段:生成Fiber树,确定需要更新的内容
  2. Commit阶段:执行DOM操作

十、setState同步异步

10.1 合成事件与钩子函数

在合成事件和钩子函数中,setState 是”异步”的:

this.setState({ count: this.state.count + 1 });
console.log(this.state.count);

this.setState({ count: this.state.count + 1 }, () => {
    console.log(this.state.count);
});

10.2 原生事件与setTimeout

在原生事件和 setTimeout 中,setState 是同步的:

document.getElementById("btn").addEventListener("click", () => {
    this.setState({ count: this.state.count + 1 });
    console.log(this.state.count);
});

setTimeout(() => {
    this.setState({ count: this.state.count + 1 });
    console.log(this.state.count);
}, 0);

10.3 批量更新

  • 同一值的多次 setState 会被覆盖
  • 不同值的 setState 会合并批量更新

10.4 异步原理揭秘

setState 的”异步”并不是说内部由异步代码实现,其实本身执行的过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值,形成了所谓的”异步”,当然可以通过第二个参数 setState(partialState, callback) 中的 callback 拿到更新后的结果。

十一、Redux核心概念

11.1 数据流

用户行为 → Action → Reducer → Store → View

11.2 核心组成

组成 说明
Store 存储所有状态
Action 描述发生的事件
Reducer 根据Action更新状态

11.3 React-Redux

组件 说明
Provider 从最外部封装整个应用,传递store
Connect 连接React组件与Redux store

Connect 的工作原理

  1. 包装原组件,将 stateaction 通过 props 的方式传入到原组件内部
  2. 监听 store tree 变化,使其包装的原组件可以响应 state 变化

十二、高阶组件

12.1 定义

高阶组件是参数为组件,返回值为新组件的函数。

function withAuth(WrappedComponent) {
    return function WithAuthComponent(props) {
        if (isAuthenticated) {
            return ;
        }
        return ;
    };
}

12.2 作用

  • 代码复用,逻辑抽象
  • 渲染劫持
  • State 抽象和更改
  • Props 更改

十三、创建组件的方式

13.1 函数组件(推荐)

const Counter = () => {
    const [count, setCount] = useState(0);

    useEffect(() => {
        document.title = `Count: ${count}`;
    }, [count]);

    return (
        

{count}

); };

13.2 类组件

class Counter extends React.Component {
    state = { count: 0 };

    increment = () => {
        this.setState({ count: this.state.count + 1 });
    };

    render() {
        return (
            

{this.state.count}

); } }

13.3 现代组件写法

写法 说明
React.memo 缓存函数组件渲染
forwardRef 传递ref给子组件
lazy 动态导入组件

十四、元素与组件的区别

概念 说明
React元素 普通对象,描述UI结构
组件 类或纯函数,由元素构成

十五、React核心特点

15.1 核心思想

  • React:函数式编程,单向数据流,数据不可变
  • 对比:Vue 采用响应式系统,数据驱动视图

15.2 模板语法

  • React:使用 JSX,将 HTML 与 JavaScript 结合,更灵活
  • 对比:Vue 使用 HTML-like 模板语法,支持指令

15.3 状态管理

方案 特点 适用场景
Redux 成熟稳定,生态完善 大型应用
Zustand 轻量级,API简洁 中小型应用
Jotai 原子化状态管理 细粒度状态管理

15.4 性能优化

优化方式 说明
memo/useMemo/useCallback 手动优化渲染性能
并发模式 React 18 新特性
编译时优化 Tree Shaking、静态提升

15.5 适用场景

  • 大型应用
  • 复杂状态管理需求
  • 需要良好的 TypeScript 支持

十六、Redux与Vuex对比

16.1 核心区别

对比项 Redux Vuex
数据可变性 不可变,每次返回新state 可变,直接修改
变化检测 订阅机制触发更新通知 getter/setter监听
适用框架 React Vue

文章作者: 弈心
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 弈心 !
评论
 上一篇
前端面试准备指南五之其他前端技术篇 前端面试准备指南五之其他前端技术篇
其他前端技术核心知识点,包括小程序开发、APP项目、认证授权、微前端等
下一篇 
前端面试准备指南八之网络安全篇 前端面试准备指南八之网络安全篇
网络安全与HTTP协议核心知识点,涵盖网络基础、HTTP协议、安全攻击及跨域通信,包括七层协议、TCP/UDP区别、HTTPS、三次握手四次挥手、HTTP版本对比、状态码、XSS/CSRF/DDoS、同源策略、跨域方案等
  目录