You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React开发中除useState外实用Hook推荐及useEffect用法解惑

React实用Hook详解(除useState外)

useEffect:核心用法与适用场景

useEffect是处理副作用的核心Hook,副作用指组件渲染完成后需要执行的操作:数据请求、DOM操作、订阅/取消订阅、定时器等。

使用时机与方法

  • 组件首次挂载后执行:给依赖数组传空数组[],只会在组件挂载时运行一次
    useEffect(() => {
      // 初始化请求数据
      const fetchUser = async () => {
        const res = await fetch('/api/user');
        const user = await res.json();
        setUser(user);
      };
      fetchUser();
    }, []);
    
  • 依赖项变化时执行:依赖数组中指定变量,当这些变量更新时重新运行副作用
    useEffect(() => {
      // 当userId变化时,重新请求用户数据
      const fetchUser = async () => {
        const res = await fetch(`/api/user/${userId}`);
        const user = await res.json();
        setUser(user);
      };
      fetchUser();
    }, [userId]); // 依赖userId,变化时触发
    
  • 组件每次渲染都执行:不传递依赖数组,会在组件每次渲染(包括挂载、更新)时都运行,除非必要否则避免使用
  • 组件卸载/依赖变化前清理:返回一个清理函数,用于取消订阅、清除定时器、取消网络请求等,防止内存泄漏
    useEffect(() => {
      const socket = io.connect('/');
      socket.on('message', setMessage);
      
      // 组件卸载或依赖变化时关闭socket连接
      return () => {
        socket.off('message', setMessage);
        socket.disconnect();
      };
    }, []);
    

其他高频实用Hook

useContext

  • 适用场景:跨多层组件共享状态(如主题、用户登录态),避免props逐层传递的繁琐
  • 示例:
    // 全局创建Context
    const UserContext = React.createContext(null);
    
    // 父组件提供Context值
    function App() {
      const [user, setUser] = useState({ name: 'Alice', id: 1 });
      return (
        <UserContext.Provider value={user}>
          <Navbar />
          <Profile />
        </UserContext.Provider>
      );
    }
    
    // 子组件直接获取Context值
    function Profile() {
      const user = useContext(UserContext);
      return <div>当前用户:{user.name}</div>;
    }
    

useReducer

  • 适用场景:处理复杂状态逻辑,比如状态包含多个子属性、状态更新依赖复杂计算、多个状态操作关联时,替代多个useState让代码更清晰
  • 示例:
    const initialState = { count: 0, step: 1 };
    
    function countReducer(state, action) {
      switch (action.type) {
        case 'increment':
          return { ...state, count: state.count + state.step };
        case 'decrement':
          return { ...state, count: state.count - state.step };
        case 'setStep':
          return { ...state, step: action.payload };
        default:
          throw new Error('未知操作类型');
      }
    }
    
    function Counter() {
      const [state, dispatch] = useReducer(countReducer, initialState);
      return (
        <div>
          <p>计数:{state.count}</p>
          <button onClick={() => dispatch({ type: 'increment' })}>+</button>
          <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
          <input 
            type="number" 
            value={state.step} 
            onChange={(e) => dispatch({ type: 'setStep', payload: Number(e.target.value) })}
          />
        </div>
      );
    }
    

useCallback

  • 适用场景:缓存函数引用,配合React.memo优化子组件渲染——避免因父组件重新渲染导致函数重新创建,进而触发子组件不必要的重渲染
  • 示例:
    function Parent() {
      const [count, setCount] = useState(0);
      // 缓存handleClick函数,只有count变化时才重新生成
      const handleClick = useCallback(() => {
        setCount(prev => prev + 1);
      }, [count]);
    
      // 子组件用React.memo包裹,只有props变化时才渲染
      return <Child onClick={handleClick} />;
    }
    
    const Child = React.memo(({ onClick }) => {
      console.log('子组件渲染');
      return <button onClick={onClick}>点击计数</button>;
    });
    

useMemo

  • 适用场景:缓存昂贵计算的结果,避免组件每次渲染都重复执行高开销计算(比如大数据量处理、复杂数学运算)
  • 示例:
    // 模拟昂贵计算
    const calculateTotal = (items) => {
      console.log('执行计算...');
      return items.reduce((sum, item) => sum + item.price, 0);
    };
    
    function Cart({ items }) {
      // 只有items变化时才重新计算总价
      const total = useMemo(() => calculateTotal(items), [items]);
      return <div>购物车总价:¥{total}</div>;
    }
    

useRef

  • 适用场景:
    1. 获取DOM元素的引用,用于操作DOM(比如聚焦输入框、获取元素尺寸)
    2. 保存跨渲染周期的可变值,修改它不会触发组件重渲染
  • 示例:
    // 获取DOM元素
    function InputAutoFocus() {
      const inputRef = useRef(null);
      useEffect(() => {
        inputRef.current.focus();
      }, []);
      return <input ref={inputRef} type="text" />;
    }
    
    // 保存跨渲染的值
    function Counter() {
      const [count, setCount] = useState(0);
      const prevCount = useRef();
    
      useEffect(() => {
        prevCount.current = count;
      }, [count]);
    
      return (
        <div>
          当前计数:{count},上一次计数:{prevCount.current}
          <button onClick={() => setCount(prev => prev + 1)}>+1</button>
        </div>
      );
    }
    

useLayoutEffect

  • 适用场景:需要在DOM更新完成后、浏览器绘制之前同步执行的操作,比如获取DOM布局信息并立即更新状态,避免页面出现视觉闪烁(和useEffect的区别是它在浏览器绘制前执行,同步阻塞渲染)
  • 示例:
    function ElementSize() {
      const [height, setHeight] = useState(0);
      const divRef = useRef(null);
    
      useLayoutEffect(() => {
        // DOM更新后立即获取高度,同步设置状态
        setHeight(divRef.current.offsetHeight);
      }, []);
    
      return <div ref={divRef}>元素高度:{height}px</div>;
    }
    

内容的提问来源于stack exchange,提问作者aqtar parveez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 17:05:28