React Hooks 常见面试题总结
React Hooks 常见面试题总结
什么是 React Hooks?
React Hooks 是 React 16.8 引入的新特性,它允许你在不编写 class 组件的情况下使用 state 以及其他的 React 特性。
Hooks 解决了 React 中长期存在的问题:
- 组件之间难以复用状态逻辑
- 复杂组件变得难以理解
- 类组件中的 this 指向问题困扰开发者
常见的 React Hooks 有哪些?
- useState: 允许函数组件使用 state
- useEffect: 处理副作用,替代 componentDidMount、componentDidUpdate 和 componentWillUnmount
- useContext: 接收一个 context 对象并返回该 context 的当前值
- useReducer: useState 的替代方案,适用于复杂的状态逻辑
- useCallback: 返回一个记忆化的回调函数,避免不必要的渲染
- useMemo: 返回一个记忆化的值,避免在每次渲染时都进行高开销的计算
- useRef: 返回一个可变的 ref 对象,其
.current
属性被初始化为传入的参数
useState 和 useReducer 的区别是什么?
- useState 适用于管理简单的状态逻辑
- useReducer 更适合处理复杂的状态逻辑,特别是当下一个状态依赖于之前的状态时
// useState 示例
const [count, setCount] = useState(0);
const increment = () => setCount(count + 1);
// useReducer 示例
const [state, dispatch] = useReducer(reducer, { count: 0 });
const increment = () => dispatch({ type: 'INCREMENT' });
function reducer(state, action) {
switch (action.type) {
case 'INCREMENT':
return { count: state.count + 1 };
default:
return state;
}
}
useEffect 的依赖数组有什么作用?
useEffect
的第二个参数是依赖数组,它决定了 effect 在什么时候执行:
- 不传依赖数组:effect 在每次渲染后都会执行
- 空依赖数组
[]
:effect 只在组件挂载时执行一次 - 有依赖的数组
[a, b]
:effect 在挂载时以及依赖项a
或b
改变时执行
// 每次渲染后执行
useEffect(() => {
document.title = `Count: ${count}`;
});
// 只在挂载时执行一次
useEffect(() => {
fetchData();
}, []);
// 当 count 改变时执行
useEffect(() => {
document.title = `Count: ${count}`;
}, [count]);
如何使用 useEffect 模拟 componentWillUnmount?
通过在 useEffect
中返回一个清理函数,可以模拟 componentWillUnmount
的行为:
useEffect(() => {
// 组件挂载时的逻辑
const subscription = someExternalAPI.subscribe();
// 返回清理函数,在组件卸载时执行
return () => {
subscription.unsubscribe();
};
}, []); // 空依赖数组确保只在挂载和卸载时执行
自定义 Hook 是什么?如何创建自定义 Hook?
自定义 Hook 是一种复用状态逻辑的机制,它不复用 state 本身,而是复用状态逻辑。
创建自定义 Hook 的步骤:
- 创建一个名称以 "use" 开头的函数
- 在函数内部可以调用其他的 Hook
- 返回需要在组件中使用的值
// 自定义 Hook: useWindowSize
function useWindowSize() {
const [size, setSize] = useState({
width: window.innerWidth,
height: window.innerHeight
});
useEffect(() => {
const handleResize = () => {
setSize({
width: window.innerWidth,
height: window.innerHeight
});
};
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
};
}, []);
return size;
}
// 在组件中使用
function MyComponent() {
const { width, height } = useWindowSize();
return (
<div>
Window size: {width} x {height}
</div>
);
}
React Hooks 的使用规则有哪些?
- 只在最顶层使用 Hook:不要在循环、条件或嵌套函数中调用 Hook
- 只在 React 函数组件或自定义 Hook 中调用 Hook:不要在普通的 JavaScript 函数中调用
- Hook 命名必须以 "use" 开头:这是一种约定,使其明显区分为一个 Hook
useCallback 和 useMemo 有什么区别?
- useCallback 返回一个记忆化的回调函数,避免在每次渲染时都创建新的函数实例
- useMemo 返回一个记忆化的值,用于避免在每次渲染时进行复杂计算
// useCallback 示例
const memoizedCallback = useCallback(() => {
doSomething(a, b);
}, [a, b]);
// useMemo 示例
const memoizedValue = useMemo(() => {
return computeExpensiveValue(a, b);
}, [a, b]);
主要区别是 useCallback
记忆的是函数,而 useMemo
记忆的是函数的执行结果。
什么情况下应该使用 useRef?
useRef
适用于以下情况:
- 访问 DOM 元素:获取对 DOM 节点的引用
- 保存不需要触发重新渲染的可变值:ref 对象的改变不会导致组件重新渲染
- 保持前一次渲染的值:因为 ref 在组件的整个生命周期内保持不变
// 访问 DOM 元素
const inputRef = useRef(null);
<input ref={inputRef} />;
// 点击按钮时让输入框获得焦点
const focusInput = () => {
inputRef.current.focus();
};
// 保存不需要触发渲染的可变值
const renderCountRef = useRef(0);
renderCountRef.current += 1;
总结
React Hooks 是现代 React 开发的核心,掌握这些基础的 Hook 及其使用场景对于面试和实际工作都非常重要。在面试中,除了了解基本用法外,理解每个 Hook 的适用场景和内部工作原理也是加分项。