以下是 React 中所有内置 Hooks 的完整分类解析,包含它们的核心作用和典型使用场景:
基础Hooks
useState
- 作用: 管理组件内部状态
- 使用:
jsx
const [count, setCount] = useState(0);
// 惰性初始化: 仅在组件第一次渲染时调用,一般用于当初始化状态是一个昂贵的操作时,或者希望仅在状态第一次使用时才计算其值
// 计算昂贵
const [theme, setTheme] = useState(() => {
// 计算昂贵的过程
});
// 第一次渲染时使用
const [theme, setTheme] = useState(() => {
const localTheme = localStorage.getItem('theme');
return localTheme ? localTheme : 'light';
});
useEffect
- 作用: 处理副作用操作
- 使用:
jsx
useEffect(() => {
/* 会在组件挂载时或依赖项更新时触发 */
/* 执行相关得副作用 */
// 返回得函数
return () => {
/* 会在组件卸载时调用 */
};
}, [deps]);
- 执行时机
会在DOM更新之后,浏览器绘制之后异步执行,不会阻塞页面得绘制,但如果在此Hook中进行了一些操作DOM的副作用处理,可能会导致页面出现闪烁的现象,如果需要解决这种现象,可以使用useLayoutEffect
Hook函数,它在DOM更新之后,与浏览器页面绘制同步执行。
useContext
- 作用: 访问Context值
- 使用
jsx
// 创建context
const myContext = React.createContext(initValue);
// 父组件
<myContextProvider value={{
name: '张三',
age: 18
}}>
...
<Child />
</myContextProvider>
// 子组件
const contextData = useContext(myContext); // { name: '张三', age: 18 }
高级状态管理
useReducer
- 作用: 复杂状态逻辑管理(类似Redux状态管理)
- 使用
jsx
const myReducer = (currState, action) => {
const { type, payload } = action;
switch(type) {
case: 'loading':
return { ...currState, loading: true };
case 'success':
return { ...currState, loading: false, data: payload };
case 'error':
return { ...state, loading: false, error: payload };
default:
return currState;
}
};
function Demo() {
const [state, dispatch] = useReducer({
isLoading: false,
data: null,
error: null,
});
const fetchData = () => {
dispatch({ type: 'loading' });
try {
const res = await fetch('https://api.example.com/data');
const data = await res.json();
dispatch({ type: ''success', payload: data });
} catch (err) {
dispatch({ type: 'error', payload: error });
}
};
useEffect(() => {
fetchData();
}, []);
return <div>...</div>
}
性能优化
useMemo
- 作用: 缓存计算结果(类似于Vue中的计算属性)
- 使用
jsx
// 对于计算过程比较复杂的值,我们可以将它进行缓存,每当组件重新渲染时,只有当依赖项变化时,我们才去重新计算,否则使用缓存的值。
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
useCallback
- 作用: 缓存回调函数引用
- 使用
jsx
// 因组件每次重新渲染时,其组件内部的函数都会重新创建,这样就会造成接收该函数的子组件进行不必要的更新,影响性能。useCallback可以保存函数的引用,只有当其依赖项发生变化时,我们才重新创建函数。
const Child = ({ onClick }) => {
console.log('update');
return <button onClick={onClick}>Click me</button>;
};
const ChildMemo = React.memo(Child);
export default function Test() {
const [count, setCount] = useState(0);
const handleClick = useCallback(() => {
console.log(count);
}, [count]);
return (
<div>
<ChildMemo onClick={handleClick} />
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
DOM/Ref操作
useRef
- 作用: 获取DOM引用/保存可变值
- 使用
jsx
const inputRef = useRef(null);
<input ref={inputRef} />
// 保存任意可变值(不会触发重新渲染)
const intervalId = useRef();
useImperativeHandle
- 作用: 自定义暴露给父组件的实例值
- 使用
jsx
import React, { useRef, useImperativeHandle, forwardRef } from 'react';
const TextInput = forwardRef((props, ref) => {
const inputRef = useRef();
// 使用 useImperativeHandle 暴露 focus 方法
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
}
}));
return <input ref={inputRef} />;
});
function ParentComponent() {
const textInputRef = useRef();
const handleFocus = () => {
// 通过 ref 调用子组件暴露的 focus 方法
textInputRef.current.focus();
};
return (
<div>
<TextInput ref={textInputRef} />
<button onClick={handleFocus}>Focus the input</button>
</div>
);
}
export default ParentComponent;
特殊场景Hooks
useLayoutEffect
- 作用: 同步DOM操作的副作用
- 使用
jsx
// 一般在DOM更新完成之后浏览器渲染之前进行一些DOM操作,避免页面出现闪速问题
useLayoutEffect(() => {
/* DOM操作 */
}, []);
React18新增Hooks
useId
- 作用: 生成唯一ID
- 使用
jsx
const id = useId();
useDeferredValue
- 作用: 延迟更新某个值
- 使用
jsx
// 适用于输入防抖等场景(列表搜索)
import React, { useState, useDeferredValue, useMemo } from 'react';
const LargeList = () => {
const [query, setQuery] = useState('');
const deferredQuery = useDeferredValue(query); // 延迟查询
const data = useMemo(() => {
// 生成一个大量的数据列表
return Array.from({ length: 10000 }, (_, index) => `Item ${index + 1}`);
}, []);
const filteredData = useMemo(() => {
// 基于延迟的查询词来过滤数据
return data.filter(item => item.toLowerCase().includes(deferredQuery.toLowerCase()));
}, [deferredQuery, data]);
return (
<div>
<input
type="text"
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Search in list"
/>
<ul>
{filteredData.map(item => (
<li key={item}>{item}</li>
))}
</ul>
</div>
);
};
export default LargeList;