level 5
作为前端开发,你是不是也觉得“类组件写着麻烦”“this绑定绕不清”?自从React 16.8推出Hooks,函数组件也能轻松用状态、生命周期,代码量直接少一半!今天用最通俗的话,带你10分钟搞懂3个必学Hook,看完就能写项目~
1. useState:让函数组件“有状态”
作用:给函数组件添加“状态变量”(比如计数器、表单输入值),相当于类组件的this.state 。
用法:
jsx复制import { useState } from 'react'; function Counter() { // 声明状态变量:[当前值, 更新函数] = useState(初始值) const [count, setCount] = useState(0); return ( <div> <p>你点了 {count} 次</p> {/* 点击按钮更新状态 */} <button onClick={() => setCount(count + 1)}>点我+1</button> </div> ); }
核心逻辑:
useState(0):初始值为0,返回一个数组,第一个元素是当前状态(count),第二个是更新函数(setCount)。
不要直接修改count!必须用setCount(newValue),React才会重新渲染组件。
初始值只在第一次渲染生效,后续渲染会忽略。
2. useEffect:处理“副作用”的万能Hook
作用:替代类组件的生命周期(componentDidMount/componentDidUpdate/componentWillUnmount),处理“副作用”(如请求数据、操作DOM、定时器)。
用法:
jsx复制import { useState, useEffect } from 'react'; function UserProfile({ userId }) { const [user, setUser] = useState(null); // 副作用函数:组件渲染后执行 useEffect(() => { // 1. 发送请求获取用户数据(副作用) const fetchUser = async () => { const res = await fetch(`https://api.example.com/user/${userId}`); const data = await res.json(); setUser(data); }; fetchUser(); // 2. 清理函数:组件卸载或userId变化时执行(如清除定时器、取消请求) return () => { console.log(' 组件要卸载啦,清理一下'); }; }, [userId]); // 依赖数组:只有userId变化时,才重新执行副作用函数 if (!user) return <p>加载中...</p>; return <div>用户名:{user.name}</div>; }
3种常见场景:
依赖数组为空[]:副作用只执行一次(相当于componentDidMount)。
依赖数组有值[userId]:初始渲染+userId变化时执行(相当于componentDidMount+componentDidUpdate)。
返回清理函数:组件卸载时执行(相当于componentWillUnmount)。
3. useRef:获取DOM元素或“跨渲染保存值”
智优达React Hooks状态管理教程
作用:两种用法——①获取DOM元素;②保存一个“不会触发渲染的变量”(类似类组件的this.xxx )。
用法:
jsx复制import { useRef, useEffect } from 'react'; function InputFocus() { // 1. 获取DOM元素 const inputRef = useRef(null); // 2. 保存跨渲染的变量(不会触发组件重新渲染) const countRef = useRef(0); useEffect(() => { // 组件渲染后,让输入框自动聚焦 inputRef.current.focus(); // 点击按钮时,countRef的值会变,但组件不会重新渲染 const timer = setInterval(() => { countRef.current++; console.log(' 定时器执行次数:', countRef.current); }, 1000); return () => clearInterval(timer); }, []); return <input ref={inputRef} placeholder="自动聚焦的输入框" />; }
关键区别:
useState更新会触发组件重新渲染,useRef更新不会。
ref.current 可以直接修改(如countRef.current++ ),无需通过“更新函数”。
实战案例:用3个Hook写一个“待办事项列表”jsx复制import { useState, useEffect, useRef } from 'react'; function TodoList() { const [todos, setTodos] = useState([]); // 待办列表状态 const [inputText, setInputText] = useState(''); // 输入框状态 const inputRef = useRef(null); // 输入框DOM引用 // 1. 从本地存储加载待办列表(组件挂载时执行) useEffect(() => { const savedTodos = localStorage.getItem('todos'); if (savedTodos) setTodos(JSON.parse(savedTodos)); }, []); // 2. 保存待办列表到本地存储(todos变化时执行) useEffect(() => { localStorage.setItem('todos', JSON.stringify(todos)); }, [todos]); // 添加待办事项 const addTodo = () => { if (!inputText.trim()) return; setTodos([...todos, { id: Date.now(), text: inputText }]); setInputText(''); // 清空输入框 inputRef.current.focus(); // 输入框重新聚焦 }; return ( <div> <input ref={inputRef} value={inputText} onChange={(e) => setInputText(e.target.value)} placeholder="输入待办事项" /> <button onClick={addTodo}>添加</button> <ul> {todos.map(todo => ( <li key={todo.id}>{todo.text}</li> ))} </ul> </div> ); }
功能拆解:
useState管理待办列表和输入框状态;
useEffect实现本地存储持久化(加载+保存);
useRef获取输入框DOM,实现添加后自动聚焦。
总结:Hooks的核心优势
代码更简洁:不用写class、this、生命周期方法,几行代码实现类组件几十行的功能。
逻辑复用方便:把重复逻辑抽成“自定义Hook”(如useLocalStorage、useTimer),直接在组件间共享。
副作用隔离:一个组件可以写多个useEffect,每个负责一个副作用,比类组件的生命周期函数更清晰。
刚开始用Hooks可能会记混规则(比如“只能在函数组件顶层调用”),但多写两个小项目就会发现——这才是React开发的“正确打开方式”!
2025年11月18日 10点11分
1
1. useState:让函数组件“有状态”
作用:给函数组件添加“状态变量”(比如计数器、表单输入值),相当于类组件的this.state 。
用法:
jsx复制import { useState } from 'react'; function Counter() { // 声明状态变量:[当前值, 更新函数] = useState(初始值) const [count, setCount] = useState(0); return ( <div> <p>你点了 {count} 次</p> {/* 点击按钮更新状态 */} <button onClick={() => setCount(count + 1)}>点我+1</button> </div> ); }
核心逻辑:
useState(0):初始值为0,返回一个数组,第一个元素是当前状态(count),第二个是更新函数(setCount)。
不要直接修改count!必须用setCount(newValue),React才会重新渲染组件。
初始值只在第一次渲染生效,后续渲染会忽略。
2. useEffect:处理“副作用”的万能Hook
作用:替代类组件的生命周期(componentDidMount/componentDidUpdate/componentWillUnmount),处理“副作用”(如请求数据、操作DOM、定时器)。
用法:
jsx复制import { useState, useEffect } from 'react'; function UserProfile({ userId }) { const [user, setUser] = useState(null); // 副作用函数:组件渲染后执行 useEffect(() => { // 1. 发送请求获取用户数据(副作用) const fetchUser = async () => { const res = await fetch(`https://api.example.com/user/${userId}`); const data = await res.json(); setUser(data); }; fetchUser(); // 2. 清理函数:组件卸载或userId变化时执行(如清除定时器、取消请求) return () => { console.log(' 组件要卸载啦,清理一下'); }; }, [userId]); // 依赖数组:只有userId变化时,才重新执行副作用函数 if (!user) return <p>加载中...</p>; return <div>用户名:{user.name}</div>; }
3种常见场景:
依赖数组为空[]:副作用只执行一次(相当于componentDidMount)。
依赖数组有值[userId]:初始渲染+userId变化时执行(相当于componentDidMount+componentDidUpdate)。
返回清理函数:组件卸载时执行(相当于componentWillUnmount)。
3. useRef:获取DOM元素或“跨渲染保存值”
智优达React Hooks状态管理教程
作用:两种用法——①获取DOM元素;②保存一个“不会触发渲染的变量”(类似类组件的this.xxx )。
用法:
jsx复制import { useRef, useEffect } from 'react'; function InputFocus() { // 1. 获取DOM元素 const inputRef = useRef(null); // 2. 保存跨渲染的变量(不会触发组件重新渲染) const countRef = useRef(0); useEffect(() => { // 组件渲染后,让输入框自动聚焦 inputRef.current.focus(); // 点击按钮时,countRef的值会变,但组件不会重新渲染 const timer = setInterval(() => { countRef.current++; console.log(' 定时器执行次数:', countRef.current); }, 1000); return () => clearInterval(timer); }, []); return <input ref={inputRef} placeholder="自动聚焦的输入框" />; }
关键区别:
useState更新会触发组件重新渲染,useRef更新不会。
ref.current 可以直接修改(如countRef.current++ ),无需通过“更新函数”。
实战案例:用3个Hook写一个“待办事项列表”jsx复制import { useState, useEffect, useRef } from 'react'; function TodoList() { const [todos, setTodos] = useState([]); // 待办列表状态 const [inputText, setInputText] = useState(''); // 输入框状态 const inputRef = useRef(null); // 输入框DOM引用 // 1. 从本地存储加载待办列表(组件挂载时执行) useEffect(() => { const savedTodos = localStorage.getItem('todos'); if (savedTodos) setTodos(JSON.parse(savedTodos)); }, []); // 2. 保存待办列表到本地存储(todos变化时执行) useEffect(() => { localStorage.setItem('todos', JSON.stringify(todos)); }, [todos]); // 添加待办事项 const addTodo = () => { if (!inputText.trim()) return; setTodos([...todos, { id: Date.now(), text: inputText }]); setInputText(''); // 清空输入框 inputRef.current.focus(); // 输入框重新聚焦 }; return ( <div> <input ref={inputRef} value={inputText} onChange={(e) => setInputText(e.target.value)} placeholder="输入待办事项" /> <button onClick={addTodo}>添加</button> <ul> {todos.map(todo => ( <li key={todo.id}>{todo.text}</li> ))} </ul> </div> ); }
功能拆解:
useState管理待办列表和输入框状态;
useEffect实现本地存储持久化(加载+保存);
useRef获取输入框DOM,实现添加后自动聚焦。
总结:Hooks的核心优势
代码更简洁:不用写class、this、生命周期方法,几行代码实现类组件几十行的功能。
逻辑复用方便:把重复逻辑抽成“自定义Hook”(如useLocalStorage、useTimer),直接在组件间共享。
副作用隔离:一个组件可以写多个useEffect,每个负责一个副作用,比类组件的生命周期函数更清晰。
刚开始用Hooks可能会记混规则(比如“只能在函数组件顶层调用”),但多写两个小项目就会发现——这才是React开发的“正确打开方式”!