返回面试题列表

React Hooks 常见面试题总结

React Hooks 常见面试题总结

什么是 React Hooks?

React Hooks 是 React 16.8 引入的新特性,它允许你在不编写 class 组件的情况下使用 state 以及其他的 React 特性。

Hooks 解决了 React 中长期存在的问题:

  • 组件之间难以复用状态逻辑
  • 复杂组件变得难以理解
  • 类组件中的 this 指向问题困扰开发者

常见的 React Hooks 有哪些?

  1. useState: 允许函数组件使用 state
  2. useEffect: 处理副作用,替代 componentDidMount、componentDidUpdate 和 componentWillUnmount
  3. useContext: 接收一个 context 对象并返回该 context 的当前值
  4. useReducer: useState 的替代方案,适用于复杂的状态逻辑
  5. useCallback: 返回一个记忆化的回调函数,避免不必要的渲染
  6. useMemo: 返回一个记忆化的值,避免在每次渲染时都进行高开销的计算
  7. 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 在什么时候执行:

  1. 不传依赖数组:effect 在每次渲染后都会执行
  2. 空依赖数组 []:effect 只在组件挂载时执行一次
  3. 有依赖的数组 [a, b]:effect 在挂载时以及依赖项 ab 改变时执行
// 每次渲染后执行
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 的步骤:

  1. 创建一个名称以 "use" 开头的函数
  2. 在函数内部可以调用其他的 Hook
  3. 返回需要在组件中使用的值
// 自定义 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 的使用规则有哪些?

  1. 只在最顶层使用 Hook:不要在循环、条件或嵌套函数中调用 Hook
  2. 只在 React 函数组件或自定义 Hook 中调用 Hook:不要在普通的 JavaScript 函数中调用
  3. 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 适用于以下情况:

  1. 访问 DOM 元素:获取对 DOM 节点的引用
  2. 保存不需要触发重新渲染的可变值:ref 对象的改变不会导致组件重新渲染
  3. 保持前一次渲染的值:因为 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 的适用场景和内部工作原理也是加分项。