useEffect
是 React 中的一个 Hook(钩子),用于在函数组件中处理副作用(side effects)。副作用指的是那些在渲染之外的操作,比如数据请求、订阅事件、手动操作 DOM 等。在类组件中,这些逻辑通常写在生命周期方法(如 componentDidMount
、componentDidUpdate
、componentWillUnmount
)中,而 useEffect
则将这些功能统一到了函数组件中。
useEffect
允许你在组件渲染后执行这些操作,并且可以选择性地清理副作用(比如取消订阅)。import React, { useState, useEffect } from 'react';
function Example() {
const [data, setData] = useState(null);
// useEffect 的基本结构
useEffect(() => {
// 副作用代码:比如获取数据
fetch('https://api.example.com/data')
.then((response) => response.json())
.then((result) => setData(result));
// 可选:返回一个清理函数
return () => {
console.log('清理副作用');
};
}, []); // 依赖数组
return <div>{data ? data.message : '加载中...'}</div>;
}
useEffect(() => {}, [])
:
依赖数组的作用:
[]
(空数组):副作用只在组件首次渲染(挂载)时运行一次,类似 componentDidMount
。[data]
(有依赖):每次 data
改变时,副作用都会重新运行,类似 componentDidUpdate
。清理函数:
componentWillUnmount
。数据获取:
useEffect(() => {
async function fetchData() {
const response = await fetch('https://api.example.com/data');
const result = await response.json();
setData(result);
}
fetchData();
}, []); // 只在挂载时请求一次
事件监听:
useEffect(() => {
const handleResize = () => console.log(window.innerWidth);
window.addEventListener('resize', handleResize);
// 清理:移除监听器
return () => window.removeEventListener('resize', handleResize);
}, []); // 只在挂载和卸载时运行
依赖状态更新:
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `点击了 ${count} 次`;
}, [count]); // 每次 count 变化时更新标题
在 Next.js 中,useEffect
的用法与普通 React 一致,但需要注意以下几点:
useEffect
只在客户端运行。如果在 SSR 中需要初始数据,建议使用 getServerSideProps
或 getStaticProps
,而不是依赖 useEffect
。useEffect
会在客户端 hydration 完成后执行,适合处理客户端特有的逻辑。useEffect
在组件渲染完成后异步执行,不会阻塞 UI 更新。eslint-plugin-react-hooks
)可以帮助检测遗漏的依赖。setInterval
),务必在清理函数中取消,以避免内存泄漏。类组件生命周期 | useEffect 等价用法 |
---|---|
componentDidMount |
useEffect(() => {}, []) |
componentDidUpdate |
useEffect(() => {}, [dep]) |
componentWillUnmount |
useEffect(() => { return () => {} }, []) |
useEffect
运行次数不符合预期,检查依赖数组是否正确。console.log
确认副作用和清理函数的执行时机。useState
是 React 中的一个 Hook(钩子),用于在函数组件中添加和管理状态(state)。在 React 的类组件中,状态通常通过 this.state
和 this.setState
来管理,而 useState
则为函数组件提供了类似的功能,让开发者可以在不使用类的情况下处理动态数据。
useState
允许你声明一个状态变量,并提供一个方法来更新它。import React, { useState } from 'react';
function Example() {
// 声明状态变量 count,初始值为 0
const [count, setCount] = useState(0);
return (
<div>
<p>你点击了 {count} 次</p>
<button onClick={() => setCount(count + 1)}>点击我</button>
</div>
);
}
useState(0)
:
useState
接受一个参数作为状态的初始值(这里是 0
)。count
):当前状态的值。setCount
):一个函数,用于更新状态。setCount
:
setCount
会更新 count
的值,并触发组件重新渲染。setCount(prevCount => prevCount + 1)
)。useState
定义的状态只属于当前组件,不会影响其他组件。setCount(prev => prev + 1)
),以避免潜在的更新冲突。管理对象状态:
import React, { useState } from 'react';
function Form() {
const [user, setUser] = useState({ name: '', age: 0 });
return (
<div>
<input
value={user.name}
onChange={(e) => setUser({ ...user, name: e.target.value })}
/>
<input
value={user.age}
onChange={(e) => setUser({ ...user, age: Number(e.target.value) })}
/>
<p>姓名: {user.name}, 年龄: {user.age}</p>
</div>
);
}
...
)保留未更改的部分,否则会覆盖整个状态。在 Next.js 中,useState
的使用与普通 React 项目完全相同,因为 Next.js 是基于 React 的框架。无论是在客户端渲染、SSR 还是 SSG 的场景下,useState
都可以用来管理组件的交互状态。不过,在 SSR 中,初始状态需要在服务器端正确初始化(通常配合 getServerSideProps
或 useEffect
)。
为什么不能在条件语句中使用 useState
?
useState
,顺序可能变化,导致状态管理混乱。初始值只生效一次:
useState
的初始值只在组件首次渲染时使用,后续更新只依赖 setState
。