Skip to content

理解渲染和副作用

渲染与副作用

渲染是指 React 根据状态和属性生成或更新 UI 的过程。

副作用是指那些任何改变外部环境或依赖外部环境的行为。它是某段代码除了完成自己的任务之外,对系统或外部环境造成的额外影响,如:

  • 读取外部状态:从服务器获取数据、访问本地存储等。
  • 修改外部状态:写入文件、更新浏览器标题、发送日至到服务器等。
  • 与外部系统交互:订阅事件、启动计时器、操作 DOM 等。
  • 引入资源或依赖:加载脚本、动态创建元素。
js
document.title = 'Hello, world!'; // 修改外部环境:改变页面标题
console.log('Log a message');    // 与外部环境交互:输出到控制台

这些操作都属于“副作用”,因为它们超出了当前逻辑的“纯粹性”。

由渲染引起的副作用

React 是一个声明式的 UI 框架,它是通过状态驱动视图。当状态或属性发生变化的时候,React 就会重新渲染组件。而某些副作用恰好需要在组件挂载(第一次渲染)或更新(后续渲染)时触发,这些副作用就称之为由渲染引起的副作用

js
import React, { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  // 副作用:更新 document.title
  useEffect(() => {
    document.title = `You clicked ${count} times`;
  }, [count]); // 依赖于 count 的变化

  return (
    <button onClick={() => setCount(count + 1)}>
      Click me
    </button>
  );
}

在这个例子中:

  • 渲染是由 count 状态变化触发的,React 会重新渲染组件。
  • 副作用是 document.title 的更新,跟渲染本身无关,但需要在渲染完成后进行。

为什么需要专门处理副作用

React 渲染组件是一个纯函数式的过程:相同的输入(状态和属性)应该始终生成相同的 UI。副作用会打破这种纯函数逻辑,例如:

  • 如果在渲染过程中直接操作 DOM,React 的虚拟 DOM 机制可能会受到干扰。
  • 副作用可能依赖外部环境或产生资源泄漏,比如事件监听没有正确清理。

因此,React 提供了 useEffect 作为处理副作用的工具,并保证它的执行是在渲染完成后,不会影响组件的渲染过程。

常见的副作用

在 React 中,副作用通常分为以下两类:

  • 需要清理的副作用:如订阅事件或设置计时器,需要在组件卸载时清理(return 一个清理函数)。
  • 不需要清理的副作用:如更新 DOM 或发起简单的网络请求。
js
useEffect(() => {
  const timer = setInterval(() => {
    console.log('Interval running');
  }, 1000);

  // 返回清理函数
  return () => clearInterval(timer);
}, []); // 依赖为空,表示只在组件挂载和卸载时触发

依赖数组

依赖数组的作用是控制副作用的执行时机

  • 空数组 []:只在组件挂载和卸载时运行一次。
  • 非空依赖数组:依赖发生变化时重新运行副作用。
  • 无依赖数组:每次渲染都会运行副作用。