理解渲染和副作用
渲染与副作用
渲染是指 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);
}, []); // 依赖为空,表示只在组件挂载和卸载时触发
依赖数组
依赖数组的作用是控制副作用的执行时机:
- 空数组
[]
:只在组件挂载和卸载时运行一次。 - 非空依赖数组:依赖发生变化时重新运行副作用。
- 无依赖数组:每次渲染都会运行副作用。