React Hooks實戰(zhàn):從useState到useContext深度解析

useState和useContext深度解析

React Hooks 徹底改變了React組件的狀態(tài)管理和功能復(fù)用方式疹鳄,使得函數(shù)組件也能擁有類組件的功能。

useState:函數(shù)組件的狀態(tài)管理

簡介:

useState是React中最基礎(chǔ)的Hook缎罢,它允許我們在函數(shù)組件中添加狀態(tài)。useState是React提供的一個內(nèi)置Hook,用于在函數(shù)組件中添加局部狀態(tài)慎宾。它接受一個初始值作為參數(shù)潜支,返回一個數(shù)組甸赃,數(shù)組的第一個元素是當(dāng)前狀態(tài),第二個元素是一個更新狀態(tài)的函數(shù)冗酿。

import React, { useState } from 'react';

function Example() {
  // 初始化狀態(tài)count為0
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

useState 返回的 setCount 函數(shù)用于更新狀態(tài)埠对。每次調(diào)用 setCount 時,React會重新渲染組件裁替,并根據(jù)新的狀態(tài)值重新生成虛擬DOM项玛,然后進(jìn)行高效的DOM diff,最終更新實際DOM弱判。

深入理解

useState的工作原理襟沮,狀態(tài)更新的異步性及其對性能的影響。

  • 狀態(tài)更新是異步的,這意味著在同一個事件循環(huán)中多次調(diào)用 setCount开伏,React只會使用最后一次的值膀跌。
  • useState 不支持復(fù)雜對象的淺比較,如果需要基于前一個狀態(tài)更新狀態(tài)固灵,可以使用函數(shù)形式的 setCount捅伤,例如 setCount(prevCount => prevCount + 1)

進(jìn)階應(yīng)用

結(jié)合useEffect處理副作用巫玻,如數(shù)據(jù)獲取與清理丛忆。

import React, { useState, useEffect } from 'react';

function Example() {
  // 初始化狀態(tài)
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  // 數(shù)據(jù)獲取函數(shù)
  const fetchData = async () => {
    try {
      setLoading(true);
      const response = await fetch('https://api.example.com/data');
      const json = await response.json();
      setData(json);
      setError(null);
    } catch (err) {
      setError(err.message);
      setData(null);
    } finally {
      setLoading(false);
    }
  };

  // useEffect監(jiān)聽data的變化,首次渲染時執(zhí)行
  useEffect(() => {
    fetchData();
  }, []);

  // 渲染UI
  if (loading) {
    return <div>Loading...</div>;
  }

  if (error) {
    return <div>Error: {error}</div>;
  }

  return (
    <div>
      <h1>Data Retrieved Successfully</h1>
      <pre>{JSON.stringify(data, null, 2)}</pre>
    </div>
  );
}

export default Example;

代碼示例解讀:首先使用 useState 創(chuàng)建了三個狀態(tài)變量:data 存儲獲取的數(shù)據(jù)大审,loading 表示數(shù)據(jù)是否正在加載蘸际,error 存儲任何可能出現(xiàn)的錯誤信息。

然后徒扶,我們定義了一個 fetchData 函數(shù)粮彤,用于異步獲取數(shù)據(jù)。這個函數(shù)中包含了錯誤處理和狀態(tài)更新邏輯姜骡。

接著导坟,我們使用 useEffect 來執(zhí)行數(shù)據(jù)獲取。useEffect 的第二個參數(shù)是一個依賴數(shù)組圈澈,這里傳入空數(shù)組意味著只在組件掛載后執(zhí)行一次惫周,即首次渲染時獲取數(shù)據(jù)。這樣可以確保在組件加載時獲取數(shù)據(jù)康栈,而不是在每次狀態(tài)更新時都重新獲取递递。

useEffect 的回調(diào)函數(shù)中,我們調(diào)用 fetchData 函數(shù)啥么。由于 fetchData 改變了 data登舞、loadingerror 的值,所以不需要將這些狀態(tài)變量添加到依賴數(shù)組中悬荣,因為它們的變化會觸發(fā)組件的重新渲染菠秒,從而自動執(zhí)行新的數(shù)據(jù)獲取。

useContext:共享狀態(tài)的上下文解決方案

簡介

useContext用于跨組件傳遞數(shù)據(jù)氯迂,無需顯式傳遞props践叠。

首先,我們需要創(chuàng)建一個Context:

import React from 'react';

const ThemeContext = React.createContext('light');

然后在組件中使用 useContext:

import React, { useContext } from 'react';
import { ThemeContext } from './ThemeContext';

function Button() {
  const theme = useContext(ThemeContext);
  
  return (
    <button style={{ backgroundColor: theme === 'dark' ? 'black' : 'white' }}>
      {theme === 'dark' ? 'Dark' : 'Light'}
    </button>
  );
}

深入理解

  • 使用 useContext的組件會在提供者(Provider)更新時重新渲染嚼蚀,即使該組件的其他狀態(tài)沒有變化禁灼。
  • 如果多個組件訂閱同一個Context,它們都會在提供者狀態(tài)改變時重新渲染轿曙,可能導(dǎo)致不必要的性能開銷匾二∠溃可以通過React.memoshouldComponentUpdate等策略優(yōu)化。
  • 為了防止濫用察藐,只在需要跨多個層級共享狀態(tài)時使用Context,否則應(yīng)優(yōu)先考慮props傳遞舟扎。

useState與useContext的組合應(yīng)用

結(jié)合 useStateuseContext分飞,我們可以創(chuàng)建一個帶有主題切換功能的計數(shù)器應(yīng)用:

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

// 創(chuàng)建ThemeContext
const ThemeContext = createContext('light');

function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light');

  return (
    <ThemeContext.Provider value={theme}>
      {children}
      <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
        Toggle Theme
      </button>
    </ThemeContext.Provider>
  );
}

function Counter() {
  const theme = useContext(ThemeContext);
  const [count, setCount] = useState(0);

  return (
    <div style={{ backgroundColor: theme === 'dark' ? 'black' : 'white' }}>
      <h1>{count}</h1>
      <button onClick={() => setCount(count + 1)}>
        Click me ({theme})
      </button>
    </div>
  );
}

function App() {
  return (
    <ThemeProvider>
      <Counter />
    </ThemeProvider>
  );
}

export default App;

代碼示例解讀:ThemeProvider 使用 useState 管理主題狀態(tài),Counter 組件通過 useContext 訂閱主題睹限,同時使用 useState 管理計數(shù)器狀態(tài)譬猫。當(dāng)主題切換時,Counter 會重新渲染羡疗,顯示對應(yīng)主題的顏色染服。

2500G計算機高級架構(gòu)師速成資料超級大禮包免費送!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末叨恨,一起剝皮案震驚了整個濱河市柳刮,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌痒钝,老刑警劉巖秉颗,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異送矩,居然都是意外死亡蚕甥,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進(jìn)店門栋荸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來菇怀,“玉大人,你說我怎么就攤上這事晌块“担” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵摸袁,是天一觀的道長钥顽。 經(jīng)常有香客問我,道長靠汁,這世上最難降的妖魔是什么蜂大? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮蝶怔,結(jié)果婚禮上奶浦,老公的妹妹穿的比我還像新娘。我一直安慰自己踢星,他們只是感情好澳叉,可當(dāng)我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般成洗。 火紅的嫁衣襯著肌膚如雪五督。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天瓶殃,我揣著相機與錄音充包,去河邊找鬼。 笑死遥椿,一個胖子當(dāng)著我的面吹牛基矮,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播冠场,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼家浇,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了碴裙?” 一聲冷哼從身側(cè)響起钢悲,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎青团,沒想到半個月后譬巫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡督笆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年芦昔,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片娃肿。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡咕缎,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出料扰,到底是詐尸還是另有隱情凭豪,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布晒杈,位于F島的核電站嫂伞,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏拯钻。R本人自食惡果不足惜帖努,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望粪般。 院中可真熱鬧拼余,春花似錦、人聲如沸亩歹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至亭姥,卻和暖如春稼钩,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背致份。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工变抽, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人氮块。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像诡宗,于是被迫代替她去往敵國和親滔蝉。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容