基础
目录
react事件绑定
on + 事件名称 = { 事件处理程序 }
const clickHandler = () => {}
return (
<button onClick={clickHandler}></button>
)
事件参数e的传入
const clickHandler = (e,name) => {}
return (
<button onClick={(e) => clickHandler(e,"jack")}></button>
)
useState
创建状态变量
count [count,setCount] = useState(0)
count 状态变量 setCount 修改状态变量的方法
const handleClick = () => {
setCount(count+1)
}
修改count 使用新count渲染UI
<button onClick={handleClick}>{count}</button>
修改对象状态
const [form,setForm] = useState({ name: 'jack'})
setForm传入全新的完整对象
const = changeForm = () => {
setForm({
...form,
name:"john"
})
}
受控表单绑定

useRef获取DOM
- useRef创建ref对象,并与JSX绑定
const inputRef = useRef(null)
<input type="text" ref={inputRef} />
- 在DOM可用时,通过inputRef.current拿到DOM对象
组件通信
父子通信
父传子
实现步骤:
- 父组件传数据 - 在子组件标签上绑定属性
//父组件
return (
<div>
<Son name={name} />
</div>
)
- 子组件接收数据 - 子组件通过props参数接收数据
function Son (props){
return <div>this is son, {props.name}</div>
}
props说明:
prop children 当我们把内容嵌套在子组件标签中时,子组件会自动在名为children的prop属性中接收该内容
<Son>
<span>this is span</span>
</Son>
子组件接收props时会有children传入<span />
子传父
父组件给子组件传递自己的get函数
function Parent() {
// 父组件的状态(将被子组件修改)
const [message, setMessage] = useState('等待子组件传递数据...');
// 1. 定义回调函数(将传递给子组件)
// 接收子组件传递的参数,并更新父组件状态
const handleChildData = (childMsg) => {
console.log('父组件收到子组件数据:', childMsg);
setMessage(`子组件说:${childMsg}`);
};
return (
<div style={{ padding: '20px', border: '1px solid #ccc' }}>
<h3>父组件</h3>
<p>子组件传递的数据:{message}</p>
{/* 2. 通过 props 将回调函数传给子组件 */}
<Child onSendData={handleChildData} />
</div>
);
}
子组件接收函数,调用函数传递数据
function Child({ onSendData }) { // 3. 接收父组件传递的回调函数
const sendDataToParent = () => {
// 4. 子组件触发回调函数,并传入要传递的数据(可以是任意类型:字符串、对象、数组等)
onSendData('Hello 爸爸~ 我是子组件!');
};
return (
<div style={{ padding: '10px', marginTop: '10px', border: '1px solid #f00' }}>
<h4>子组件</h4>
{/* 点击按钮触发传递数据 */}
<button onClick={sendDataToParent}>向父组件传递数据</button>
</div>
);
}
export default Child;
兄弟通信

跨层通信

- 使用createContext方法创建一个上下文对象Ctx
const MsgContext = createContext()
- 在顶层组件(App)中通过 Ctx.Provider 组件提供数据
function App(){
const msg = "this is app msg"
return(
<div>
<MsgContext.Provider value={msg}>
<A />
</MsgContext.Provider>
</div>
)
}
- 在底层组件(B)中通过 useContext 钩子函数获取消费数据
function B(){
const msg = useContext(MsgContext)
return(
<div>
{msg}
</div>
)
}

useEffect
useEffect 是 React Hooks 中用于处理副作用的核心 Hook,它允许你在函数组件中执行数据获取、订阅、DOM 操作、清理定时器等“副作用”操作,替代了类组件中的 componentDidMount、componentDidUpdate、componentWillUnmount 三个生命周期方法。
一、核心概念
- 副作用:指组件渲染之外的操作(如网络请求、DOM 操作、订阅/监听、定时器/计时器等)。
- 依赖数组:控制
useEffect何时执行的关键,决定了副作用的触发时机。 - 清理函数:可选的返回函数,用于清除副作用(如取消订阅、清除定时器),避免内存泄漏。
二、基本语法
useEffect(() => {
// 副作用逻辑(如数据请求、DOM 操作、定时器等)
// 可选:清理函数(组件卸载或依赖变化前执行)
return () => {
// 清理操作(如清除定时器、取消订阅)
};
}, [依赖数组]); // 控制触发时机的依赖项列表
三、常见用法(按依赖数组分类)
useEffect 的行为完全由依赖数组决定,以下是 4 种核心用法:
1. 无依赖数组:每次渲染后执行(不推荐)
useEffect(() => {
console.log("每次组件渲染后都会执行");
});
- 触发时机:组件首次渲染 + 每次状态/Props 变化导致的重新渲染后。
- 风险:可能导致无限循环(如副作用中修改了依赖的状态),除非明确需要,否则避免使用。
2. 空依赖数组:仅首次渲染后执行(替代 componentDidMount)
import { useEffect } from "react";
function MyComponent() {
useEffect(() => {
console.log("组件首次渲染后执行(只跑一次)");
// 常见场景:初始化数据请求、创建订阅、启动定时器
const timer = setInterval(() => console.log("定时器运行中"), 1000);
// 清理函数:组件卸载前执行(替代 componentWillUnmount)
return () => {
clearInterval(timer); // 清除定时器,避免内存泄漏
console.log("组件卸载,清理副作用");
};
}, []); // 空数组 = 仅依赖组件挂载/卸载
return <div>Hello useEffect</div>;
}
- 触发时机:仅首次渲染后执行一次。
- 清理函数:仅在组件卸载前执行一次(用于清除副作用)。
3. 有依赖数组:依赖变化时执行(替代 componentDidUpdate)
import { useState, useEffect } from "react";
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
// 依赖 userId,当 userId 变化时重新请求数据
const fetchUser = async () => {
const res = await fetch(`/api/users/${userId}`);
const data = await res.json();
setUser(data);
};
fetchUser();
// 清理函数:userId 变化前或组件卸载前执行
return () => {
console.log("清理上一次的请求(如取消请求)");
};
}, [userId]); // 依赖数组:仅当 userId 变化时,重新执行副作用
return <div>{user ? user.name : "加载中..."}</div>;
}
- 触发时机:
- 首次渲染后执行一次;
- 依赖数组中的任意一项发生变化时,先执行上一次的清理函数,再执行新的副作用逻辑。
- 关键:依赖数组必须包含副作用中使用的所有外部变量(状态、Props、局部变量等),否则会导致闭包陷阱(使用旧值)。
4. 清理函数的完整场景
清理函数的核心作用是“消除副作用的残留影响”,常见场景:
- 清除定时器/计时器(
setInterval/setTimeout); - 取消网络请求(
AbortController); - 移除 DOM 事件监听(
removeEventListener); - 取消订阅(如 Redux 订阅、WebSocket 订阅)。
示例:取消网络请求 + 移除事件监听
useEffect(() => {
// 1. 网络请求(支持取消)
const controller = new AbortController();
const signal = controller.signal;
const fetchData = async () => {
try {
const res = await fetch("/api/data", { signal });
const data = await res.json();
console.log(data);
} catch (err) {
if (err.name !== "AbortError") console.error(err);
}
};
fetchData();
// 2. DOM 事件监听
const handleScroll = () => console.log("滚动了");
window.addEventListener("scroll", handleScroll);
// 清理函数:依赖变化/组件卸载时执行
return () => {
controller.abort(); // 取消网络请求
window.removeEventListener("scroll", handleScroll); // 移除事件监听
};
}, [依赖项]);
四、关键注意事项
1. 依赖数组必须完整
副作用中使用的所有外部变量(状态、Props、组件内定义的函数/变量)都必须加入依赖数组,否则 React 会警告,且可能导致逻辑错误(闭包陷阱)。
❌ 错误示例(遗漏依赖):
const [count, setCount] = useState(0);
const msg = `当前计数:${count}`;
useEffect(() => {
console.log(msg); // msg 依赖 count,但未加入依赖数组
}, []); // 警告:缺少依赖 msg/count
✅ 正确示例:
useEffect(() => {
const msg = `当前计数:${count}`;
console.log(msg);
}, [count]); // 依赖 count,count 变化时重新执行
2. 避免无限循环
如果副作用中修改了依赖数组中的变量,会导致:依赖变化 → 副作用执行 → 依赖再变化 → 副作用再执行… 无限循环。
❌ 错误示例(无限循环):
const [count, setCount] = useState(0);
useEffect(() => {
setCount(count + 1); // 副作用修改了依赖 count
}, [count]); // count 变化 → 副作用执行 → 无限循环
✅ 解决:使用函数式更新(不依赖外部 count):
useEffect(() => {
setCount(prev => prev + 1); // 函数式更新,不依赖外部 count
}, []); // 空数组,仅执行一次
3. 清理函数的执行时机
清理函数不是只在组件卸载时执行!当依赖数组变化时,会先执行上一次副作用的清理函数,再执行新的副作用逻辑。
示例:
useEffect(() => {
console.log("副作用执行(userId:", userId, ")");
return () => console.log("清理(旧 userId:", userId, ")");
}, [userId]);
- 当
userId从 1 变为 2 时,执行顺序:- 清理(旧 userId:1)
- 副作用执行(userId:2)
4. useEffect 是异步的
useEffect 的副作用逻辑是在组件渲染完成后异步执行的,不会阻塞 DOM 渲染(区别于 useLayoutEffect,后者是同步执行)。
示例:
useEffect(() => {
console.log("useEffect 执行(异步)");
});
console.log("组件渲染同步代码");
// 执行顺序:组件渲染同步代码 → useEffect 执行(异步)
五、与类组件生命周期的对应关系
| useEffect 用法 | 类组件生命周期等价 |
|---|---|
useEffect(() => {}, []) | componentDidMount + componentWillUnmount |
useEffect(() => {}) | componentDidMount + componentDidUpdate |
useEffect(() => { return () => {} }, [deps]) | componentDidUpdate(依赖变化) + componentWillUnmount |
总结
useEffect用于处理组件的副作用,核心是依赖数组和清理函数。- 依赖数组控制触发时机:空数组(仅挂载)、有值(依赖变化)、无数组(每次渲染)。
- 清理函数用于清除副作用残留,避免内存泄漏。
- 必须保证依赖数组完整,避免闭包陷阱和无限循环。
掌握 useEffect 是 React 函数组件开发的核心,实际开发中需结合数据请求、事件监听、定时器等场景灵活使用。