最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

速通React之Hooks的實現(xiàn)

 更新時間:2026年06月17日 09:26:18   作者:林希_Rachel_傻希希  
本文系統(tǒng)梳理 React 中 8 個最常用的核心 Hooks:useState、useReducer、useContext、useEffect、useRef、useImperativeHandle、useMemo、useCallback,下面就一起來了解一下

本文系統(tǒng)梳理 React 中 8 個最常用的核心 Hooks:useState、useReducer、useContext、useEffect、useRef、useImperativeHandle、useMemo、useCallback。從底層運行機制到高階實戰(zhàn)用法,配合完整可運行的代碼塊,助你徹底掌握函數(shù)式組件的開發(fā)精髓。

前言

React 16.8 正式引入 Hooks,使得函數(shù)組件擁有了類組件的全部能力(狀態(tài)、生命周期、上下文等),同時摒棄了類組件中 this 指向混亂、邏輯復(fù)用困難(HOC / Render Props)等問題。Hooks 的本質(zhì)是將組件狀態(tài)邏輯與視圖邏輯進行解耦,其底層依賴 React 內(nèi)部的 Fiber 架構(gòu),通過鏈表(memoizedState)來按順序存儲各個 Hook 的狀態(tài)值。

核心鐵律(必須遵守)

  1. 只在 React 函數(shù)組件或自定義 Hook 中調(diào)用 Hooks。
  2. 只在頂層調(diào)用 Hooks(不在循環(huán)、條件或嵌套函數(shù)中),以保證 Hooks 的調(diào)用順序在每次渲染中一致。

1. useState —— 響應(yīng)式狀態(tài)的基石

原理

useState 是 React 內(nèi)部狀態(tài)管理的最小單元。在 Fiber 節(jié)點上,狀態(tài)以單向鏈表的形式存儲。每次渲染時,React 根據(jù) Hook 的調(diào)用順序依次從鏈表上讀取對應(yīng)的狀態(tài)值。setState 會觸發(fā)組件重新渲染,并生成新的 Fiber 樹。

作用

為函數(shù)組件添加內(nèi)部狀態(tài),狀態(tài)改變時 UI 自動更新。

語法

const [state, setState] = useState(initialState);
  • 支持函數(shù)式更新:setState(prev => prev + 1) 可避免因閉包導(dǎo)致的狀態(tài)過期問題。

示例

import { useState } from 'react';

function UserForm() {
  const [username, setUsername] = useState('');
  const [age, setAge] = useState(18);

  const handleSubmit = () => {
    alert(`用戶名:${username},年齡:${age}`);
  };

  return (
    <div>
      <input 
        value={username} 
        onChange={(e) => setUsername(e.target.value)} 
        placeholder="請輸入用戶名" 
      />
      <input 
        type="number" 
        value={age} 
        onChange={(e) => setAge(Number(e.target.value))} 
      />
      <button onClick={handleSubmit}>提交</button>
    </div>
  );
}

2. useReducer —— 復(fù)雜狀態(tài)邏輯的治理專家

原理

與 useState 共享底層狀態(tài)存儲機制,但將狀態(tài)更新邏輯集中到 reducer 純函數(shù)中。通過 dispatch 派發(fā) action,reducer 根據(jù) action.type 計算出新狀態(tài)。這種模式源自 Redux,讓狀態(tài)變化可預(yù)測、可追蹤

作用

  • 當(dāng)狀態(tài)更新邏輯包含多個子值或復(fù)雜轉(zhuǎn)換(如購物車、表單校驗)時,比 useState 更具可讀性。
  • 適合狀態(tài)更新依賴先前狀態(tài),且操作類型多樣(增、刪、改、重置)的場景。

語法

const [state, dispatch] = useReducer(reducer, initialArg, init);

示例:購物車數(shù)量管理

import { useReducer } from 'react';

// 1. 定義 reducer
function cartReducer(state, action) {
  switch (action.type) {
    case 'ADD':
      return { ...state, count: state.count + 1 };
    case 'SUBTRACT':
      return { ...state, count: Math.max(0, state.count - 1) };
    case 'RESET':
      return { ...state, count: 0 };
    default:
      return state;
  }
}

function ShoppingCart() {
  const [state, dispatch] = useReducer(cartReducer, { count: 0 });

  return (
    <div style={{ display: 'flex', gap: '12px', alignItems: 'center' }}>
      <button onClick={() => dispatch({ type: 'SUBTRACT' })}>-</button>
      <span>數(shù)量:{state.count}</span>
      <button onClick={() => dispatch({ type: 'ADD' })}>+</button>
      <button onClick={() => dispatch({ type: 'RESET' })}>重置</button>
    </div>
  );
}

3. useContext —— 跨層級數(shù)據(jù)傳遞的直通車

原理

useContext 基于 React 的 Context API。當(dāng)上層組件通過 <Provider value={...}> 提供數(shù)據(jù)時,React 會在 Fiber 節(jié)點上維護一個 context 鏈。下層調(diào)用 useContext 會向上查找最近的 Provider,并訂閱其值。當(dāng) Provider 的 value 變化時,所有訂閱該 Context 的組件會觸發(fā)更新。

作用

徹底解決 Props Drilling(屬性鉆?。﹩栴},讓數(shù)據(jù)在組件樹中無障礙傳遞,常用于主題、語言環(huán)境、用戶鑒權(quán)信息等全局?jǐn)?shù)據(jù)。

語法

const MyContext = React.createContext(defaultValue);
const value = useContext(MyContext);

示例:全局主題切換

import { createContext, useContext, useState } from 'react';

// 1. 創(chuàng)建 Context
const ThemeContext = createContext({ theme: 'light', toggleTheme: () => {} });

// 2. 提供者組件
function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light');
  const toggleTheme = () => {
    setTheme((t) => (t === 'light' ? 'dark' : 'light'));
  };

  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}

// 3. 深層子組件消費
function ThemedButton() {
  const { theme, toggleTheme } = useContext(ThemeContext);
  const isDark = theme === 'dark';

  return (
    <button
      onClick={toggleTheme}
      style={{
        background: isDark ? '#333' : '#fff',
        color: isDark ? '#fff' : '#000',
        padding: '8px 16px',
        border: '1px solid #ccc',
        cursor: 'pointer',
      }}
    >
      當(dāng)前主題:{theme},點擊切換
    </button>
  );
}

function Toolbar() {
  return <ThemedButton />; // 中間組件無需透傳任何 props
}

// 4. 使用
export default function App() {
  return (
    <ThemeProvider>
      <Toolbar />
    </ThemeProvider>
  );
}

4. useEffect —— 副作用與生命周期的統(tǒng)一管理

原理

useEffect 的調(diào)度基于 Fiber 的 Effect List。在瀏覽器完成布局與繪制之后,React 會異步執(zhí)行 Effect 函數(shù)(默認(rèn))。通過依賴數(shù)組,React 使用 Object.is 比較前后依賴項,決定是否跳過執(zhí)行。清理函數(shù)會在組件卸載或下一次 Effect 執(zhí)行之前調(diào)用,用于清除定時器、取消訂閱等。

作用

  • 替代類組件生命周期:componentDidMount(空依賴)、componentDidUpdate(指定依賴)、componentWillUnmount(清理函數(shù))。
  • 執(zhí)行數(shù)據(jù)獲取、手動 DOM 操作、訂閱事件等副作用。

語法

useEffect(() => {
  // 副作用邏輯
  return () => {
    // 清理邏輯(可選)
  };
}, [dependencies]);

示例:獲取用戶數(shù)據(jù)并設(shè)置定時器

import { useState, useEffect } from 'react';

function UserProfile() {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    let isMounted = true; // 防止組件卸載后依然 setState

    // 模擬異步請求
    const fetchData = async () => {
      try {
        const response = await new Promise((resolve) =>
          setTimeout(() => resolve({ name: '王五', age: 30 }), 2000)
        );
        if (isMounted) {
          setUser(response);
          setLoading(false);
        }
      } catch (error) {
        if (isMounted) setLoading(false);
      }
    };

    fetchData();

    // 清理函數(shù):組件卸載時取消掛載標(biāo)記
    return () => {
      isMounted = false;
    };
  }, []); // 僅在掛載時執(zhí)行一次

  if (loading) return <p>加載中...</p>;
  return (
    <div>
      <h2>用戶信息</h2>
      <p>姓名:{user.name}</p>
      <p>年齡:{user.age}</p>
    </div>
  );
}

5. useRef —— 存儲可變數(shù)據(jù)與 DOM 引用

原理

useRef 返回一個 { current: initialValue } 對象。該對象在組件的整個生命周期內(nèi)內(nèi)存地址恒定(類似類組件的實例屬性)。修改 current 不會觸發(fā)組件重新渲染,這使得它非常適合存儲“不影響視圖”的可變數(shù)據(jù)。

作用

  • 獲取 DOM 元素的引用(如聚焦、測量尺寸)。
  • 存儲上一次渲染的值、定時器 ID、WebSocket 實例等跨渲染周期數(shù)據(jù)。

語法

const refContainer = useRef(initialValue);
// 使用:refContainer.current

示例一:自動聚焦輸入框

import { useRef, useEffect } from 'react';

function AutoFocusInput() {
  const inputRef = useRef(null);

  useEffect(() => {
    inputRef.current.focus();
  }, []);

  return <input ref={inputRef} placeholder="頁面加載后自動聚焦" />;
}

示例二:保存計時器 ID 并清除

import { useRef, useState } from 'react';

function Timer() {
  const [seconds, setSeconds] = useState(0);
  const timerIdRef = useRef(null);

  const start = () => {
    if (timerIdRef.current) return; // 防止重復(fù)啟動
    timerIdRef.current = setInterval(() => {
      setSeconds((prev) => prev + 1);
    }, 1000);
  };

  const stop = () => {
    clearInterval(timerIdRef.current);
    timerIdRef.current = null;
  };

  return (
    <div>
      <p>計時:{seconds} 秒</p>
      <button onClick={start}>開始</button>
      <button onClick={stop}>停止</button>
    </div>
  );
}

6. useImperativeHandle —— 封裝子組件的命令式接口

原理

useImperativeHandle 必須與 forwardRef 配合。父組件傳遞的 ref 對象會被子組件接收,useImperativeHandle 允許子組件自定義掛載到 ref.current 上的內(nèi)容(通常是一個方法對象)。這通過劫持 ref 的映射過程實現(xiàn),防止父組件直接操作子組件的 DOM 或內(nèi)部狀態(tài),增強封裝性。

作用

  • 暴露特定方法給父組件(如 focus、resetvalidate)。
  • 控制父組件對子組件的訪問權(quán)限,避免破壞子組件的內(nèi)部邏輯。

語法

useImperativeHandle(ref, () => ({
  // 返回暴露的方法
}), [dependencies]);

示例:父組件調(diào)用子組件表單重置與聚焦

import { forwardRef, useImperativeHandle, useRef, useState } from 'react';

// 子組件
const CustomInput = forwardRef((props, ref) => {
  const [value, setValue] = useState('');
  const inputRef = useRef(null);

  // 暴露方法給父組件
  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current.focus();
    },
    reset: () => {
      setValue('');
      inputRef.current.focus();
    },
    getValue: () => value,
  }));

  return (
    <input
      ref={inputRef}
      value={value}
      onChange={(e) => setValue(e.target.value)}
      placeholder="子組件輸入框"
    />
  );
});

// 父組件
function ParentForm() {
  const childRef = useRef(null);

  const handleReset = () => {
    childRef.current.reset();
  };

  const handleGetValue = () => {
    alert(childRef.current.getValue());
  };

  return (
    <div>
      <CustomInput ref={childRef} />
      <button onClick={handleReset}>重置并聚焦</button>
      <button onClick={handleGetValue}>獲取子組件值</button>
    </div>
  );
}

7. useMemo —— 記憶化計算結(jié)果,提升渲染性能

原理

useMemo 利用閉包存儲上一次的返回值。在渲染階段,React 會對比依賴項數(shù)組,若依賴未變,直接返回緩存的舊值,跳過函數(shù)執(zhí)行。其緩存掛載在 Fiber 節(jié)點的 memoizedState 上,屬于渲染期間的計算優(yōu)化。

作用

  • 緩存高開銷的計算(如大數(shù)據(jù)過濾、復(fù)雜數(shù)學(xué)運算)。
  • 保持引用類型的穩(wěn)定性(如對象、數(shù)組),避免因每次渲染重新創(chuàng)建而導(dǎo)致子組件(React.memo)無效重繪。

語法

const memoizedValue = useMemo(() => compute(a, b), [a, b]);

示例:大數(shù)據(jù)過濾與輸入框絲滑交互

import { useState, useMemo } from 'react';

function FilterList() {
  const [keyword, setKeyword] = useState('');
  const [count, setCount] = useState(0);

  // 模擬一個龐大的靜態(tài)數(shù)據(jù)列表
  const allItems = useMemo(() => {
    const items = [];
    for (let i = 0; i < 20000; i++) {
      items.push(`商品-${i}`);
    }
    return items;
  }, []); // 只在首次渲染生成一次

  // 根據(jù)關(guān)鍵詞過濾(僅當(dāng) keyword 或 allItems 變化時重新計算)
  const filteredItems = useMemo(() => {
    console.log('執(zhí)行過濾計算...');
    if (!keyword) return allItems;
    return allItems.filter((item) => item.includes(keyword));
  }, [keyword, allItems]);

  return (
    <div>
      <input
        value={keyword}
        onChange={(e) => setKeyword(e.target.value)}
        placeholder="輸入關(guān)鍵詞過濾(體驗絲滑輸入)"
      />
      <button onClick={() => setCount((c) => c + 1)}>重渲染計數(shù)器:{count}</button>
      <ul style={{ height: '300px', overflow: 'auto', border: '1px solid #ccc' }}>
        {filteredItems.slice(0, 100).map((item) => (
          <li key={item}>{item}</li>
        ))}
        {filteredItems.length > 100 && <li>...僅顯示前100條</li>}
      </ul>
    </div>
  );
}

點擊計數(shù)器改變 count 時,組件重渲染,但 filteredItems 因依賴未變直接命中緩存,列表不會重新過濾,輸入框交互依然絲滑。

8. useCallback —— 記憶化函數(shù)引用,優(yōu)化子組件渲染

原理

useCallback 本質(zhì)是 useMemo(() => fn, deps) 的語法糖,返回的是一個記憶化的函數(shù)。當(dāng)依賴項不變時,函數(shù)的引用地址保持不變。

作用

  • 當(dāng)父組件重渲染時,傳遞給 React.memo 子組件的回調(diào)函數(shù)引用不變,子組件得以跳過渲染。
  • 作為 useEffect 的依賴項時,避免因函數(shù)重新創(chuàng)建而導(dǎo)致 Effect 頻繁執(zhí)行。

語法

const memoizedCallback = useCallback(() => {
  doSomething(a, b);
}, [a, b]);

示例:配合 React.memo 避免子組件無效重繪

import { useState, useCallback, memo } from 'react';

// 子組件用 memo 包裹,進行淺層 props 比較
const Child = memo(({ onAdd, label }) => {
  console.log(`Child ${label} 渲染了`);
  return <button onClick={onAdd}>增加 {label}</button>;
});

function Parent() {
  const [countA, setCountA] = useState(0);
  const [countB, setCountB] = useState(0);
  const [text, setText] = useState('');

  // 使用 useCallback 緩存,依賴為空,函數(shù)永遠不變
  const handleAddA = useCallback(() => {
    setCountA((prev) => prev + 1);
  }, []);

  // 此處故意不使用 useCallback,每次渲染都會創(chuàng)建新函數(shù)
  const handleAddB = () => {
    setCountB((prev) => prev + 1);
  };

  return (
    <div>
      <input
        value={text}
        onChange={(e) => setText(e.target.value)}
        placeholder="在此輸入,觀察子組件渲染情況"
      />
      <p>Count A: {countA}</p>
      <p>Count B: {countB}</p>
      <Child onAdd={handleAddA} label="A (優(yōu)化)" />
      <Child onAdd={handleAddB} label="B (未優(yōu)化)" />
    </div>
  );
}

當(dāng)在輸入框中打字時,父組件重渲染。Child A 因 handleAddA 引用不變,不會重新渲染;Child B 因每次接收新的 handleAddB 函數(shù),導(dǎo)致 props 變化,觸發(fā)不必要的重渲染。

擴展補充:React.memo(非 Hook,但密切配合)

React.memo 是一個高階組件(HOC),用于緩存組件。它對 props 進行淺層比較,若 props 未變則跳過本次渲染。常與 useCallback 和 useMemo 組成性能優(yōu)化的“鐵三角”。

const MyComponent = memo(function MyComponent(props) {
  // 僅當(dāng) props 改變時才重新渲染
});

完整總結(jié)對照表

Hook 名稱核心職責(zé)典型應(yīng)用場景
useState管理簡單局部響應(yīng)式狀態(tài)表單輸入、開關(guān)、計數(shù)器
useReducer管理含有復(fù)雜邏輯的局部狀態(tài)購物車、具有多種操作類型的對象狀態(tài)
useContext跨組件樹共享數(shù)據(jù),避免 Props 透傳主題、語言、用戶認(rèn)證信息
useEffect執(zhí)行副作用與生命周期管理數(shù)據(jù)請求、DOM 操作、訂閱與清理
useRef存儲可變數(shù)據(jù)(不觸發(fā)渲染)及 DOM 引用獲取 DOM 節(jié)點、保存定時器 ID、記錄上一次值
useImperativeHandle自定義暴露給父組件的實例方法封裝表單組件、暴露 focus / reset 方法
useMemo記憶化計算結(jié)果,緩存對象/數(shù)組引用大數(shù)據(jù)計算、穩(wěn)定子組件 props
useCallback記憶化函數(shù)引用,配合 memo 優(yōu)化傳遞給子組件的回調(diào)函數(shù)

進階提示(并非全部,但值得了解)

除了上述 8 個核心 Hook,React 還提供了:

  • useLayoutEffect:與 useEffect 類似,但在 DOM 更新后、瀏覽器繪制前同步執(zhí)行,適合處理 DOM 尺寸測量等需要避免閃爍的操作。
  • useDebugValue:在 React DevTools 中為自定義 Hook 顯示標(biāo)簽,方便調(diào)試。
  • useId:生成穩(wěn)定且唯一的 ID,用于 SSR 場景下的無障礙屬性(如 aria-describedby)。
  • useTransition / useDeferredValue:用于并發(fā)模式下的 UI 更新降級與渲染優(yōu)化。

到此這篇關(guān)于速通React之Hooks的實現(xiàn)的文章就介紹到這了,更多相關(guān)React Hooks內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 在React中與后端API進行交互的操作步驟

    在React中與后端API進行交互的操作步驟

    在現(xiàn)代Web開發(fā)中,前后端分離的架構(gòu)已經(jīng)成為一種趨勢,React,作為一種流行的前端庫,常常與后端API進行交互,以實現(xiàn)動態(tài)數(shù)據(jù)更新和用戶體驗優(yōu)化,本文將深入探討如何在React應(yīng)用中與后端API進行交互,需要的朋友可以參考下
    2025-02-02
  • React報錯之Parameter event implicitly has an any type解決

    React報錯之Parameter event implicitly has a

    這篇文章主要為大家介紹了React報錯之Parameter event implicitly has an any type,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08
  • 詳解如何在Remix 中使用 tailwindcss

    詳解如何在Remix 中使用 tailwindcss

    這篇文章主要為大家介紹了如何在Remix中使用tailwindcss方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-05-05
  • 詳解基于React.js和Node.js的SSR實現(xiàn)方案

    詳解基于React.js和Node.js的SSR實現(xiàn)方案

    這篇文章主要介紹了詳解基于React.js和Node.js的SSR實現(xiàn)方案,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • react 國際化的實現(xiàn)代碼示例

    react 國際化的實現(xiàn)代碼示例

    這篇文章主要介紹了react 國際化的實現(xiàn)代碼示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-09-09
  • React實現(xiàn)錨點跳轉(zhuǎn)組件附帶吸頂效果的示例代碼

    React實現(xiàn)錨點跳轉(zhuǎn)組件附帶吸頂效果的示例代碼

    這篇文章主要為大家詳細介紹了React如何實現(xiàn)移動端錨點跳轉(zhuǎn)組件附帶吸頂效果,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起了解一下
    2023-01-01
  • 在?React?Native?中給第三方庫打補丁的過程解析

    在?React?Native?中給第三方庫打補丁的過程解析

    這篇文章主要介紹了在?React?Native?中給第三方庫打補丁的過程解析,有時使用了某個React Native 第三方庫,可是它有些問題,我們不得不修改它的源碼,本文介紹如何修改源碼又不會意外丟失修改結(jié)果的方法,需要的朋友可以參考下
    2022-08-08
  • 詳解React Hooks是如何工作的

    詳解React Hooks是如何工作的

    React Hooks是在React 16.8版本新增的特性,在我看了React官網(wǎng)和一些博客對React Hook的講解后還是覺得沒有g(shù)et到本質(zhì)。本篇博客通過手動實現(xiàn)useState()來了解Hook的原理和本質(zhì)。閱讀此篇博客的前提是你要知道一些 React Hooks的基本用法和使用規(guī)則,不然會看得云里霧里。
    2021-05-05
  • React?Hooks使用startTransition與useTransition教程示例

    React?Hooks使用startTransition與useTransition教程示例

    這篇文章主要為大家介紹了React?Hooks使用startTransition與useTransition教程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-01-01
  • Redis數(shù)據(jù)結(jié)構(gòu)面試高頻問題解析

    Redis數(shù)據(jù)結(jié)構(gòu)面試高頻問題解析

    這篇文章主要為大家介紹了Redis數(shù)據(jù)結(jié)構(gòu)高頻面試問題解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-06-06

最新評論

宜兴市| 康乐县| 斗六市| 南乐县| 龙口市| 咸丰县| 闵行区| 河间市| 正安县| 南部县| 宝丰县| 张家口市| 汪清县| 资溪县| 凤台县| 保亭| 海南省| 洪湖市| 米易县| 彭水| 罗平县| 武宣县| 明光市| 永修县| 临西县| 江达县| 樟树市| 河北区| 吐鲁番市| 同仁县| 江都市| 洪洞县| 南汇区| 开鲁县| 拉孜县| 射洪县| 晋州市| 大方县| 饶阳县| 武平县| 玉门市|