React hooks-useState

目錄

一.思考

二. 舉例

三.驗(yàn)證

四.小結(jié)


一.首先不太了解的先看官方文檔 本文的目的逻谦,是想通過一個(gè)簡單的例子詳細(xì)分析一些令人疑惑的問題及其背后的原因舵变。

思考: 先來看個(gè)例子

function Counter() {
    const [count, setCount] = useState(0);
    useEffect(() => {
        const id = setInterval(() => {
            // console.log(count);
            setCount(count + 1);
        }, 1000);
    }, []);

    return <h1>{count}</h1>;
}

我們期望袱讹,useEffect只執(zhí)行一次面睛,且后續(xù)每隔1s,count自動(dòng)+1,然而冲甘,實(shí)際上count從0到1后绩卤,再?zèng)]有變化,一直都是1江醇。
難道setInterval沒有執(zhí)行濒憋,于是我們帶著疑惑加上了console.log


image

事實(shí)是,setInterval每次執(zhí)行的時(shí)候嫁审,拿到的count都得0,很自然的我們會(huì)想到閉包赖晶,但是閉包能完全解釋這個(gè)現(xiàn)象嗎律适?
我們稍加修改再看下這個(gè)例子:

function Counter() {
    const [count, setCount] = useState(0);
    let num = 0;
    useEffect(() => {
        const id = setInterval(() => {
            // 通過 num 來給 count 提供值
            console.log(num);
            setCount(++num);
        }, 1000);
    }, []);

    return <h1>{count}</h1>;
}
image

我們可以看到,借助num 這個(gè)中間變量遏插,我們可以得到想要的結(jié)果捂贿。但是,同樣是閉包胳嘲,為什么num就能記住之前的的值呢厂僧?
其實(shí)問題出在count上,繼續(xù)往下看:

function Counter() {
    // ...
    console.log('我是 num', num);

    return <h1>{count}-----{num}</h1>;
}
image

渲染的num和定時(shí)器中的 num 為什么不一樣呢了牛?

每次都是重新執(zhí)行

到這里我想說的到底是什么呢颜屠?
我們可以清晰的看到渲染出的num和setinterval中的num,是不同的鹰祸。
這是因?yàn)樵赗eact中甫窟,對(duì)于函數(shù)式組件來講,每次更新都會(huì)重新執(zhí)行一次函數(shù)蛙婴。也就是說粗井,每次更新都會(huì)在當(dāng)前作用域重新聲明一個(gè) let num=0,所以街图,定時(shí)器中閉包引用的那個(gè)num,和每次更新時(shí)渲染的num,根本不是同一個(gè)浇衬。當(dāng)然,我們能很輕易地把他們變成同一個(gè)餐济。

let num = 0; // 將聲明放到渲染組件外面
function Counter() {
    // ...
    return <h1>{count}-----{num}</h1>;
}

嗯耘擂,說了這么多,跟count 有什么關(guān)系呢絮姆?
同理梳星,正因?yàn)楹瘮?shù)組件每次都會(huì)整體重新執(zhí)行赞赖,那么HOOKS當(dāng)然也是這樣。

function Counter() {
    const [count, setCount] = useState(0);
    // ...
}

useState應(yīng)該理解為和普通的javascript函數(shù)一樣冤灾,而不是React的什么黑魔法函數(shù)組件更新的時(shí)候前域,useState會(huì)重新執(zhí)行,對(duì)應(yīng)的韵吨,也會(huì)重新聲明[count, setCount]這一組常量匿垄。只不過React對(duì)這個(gè)函數(shù)做了一些特殊處理,比如:
首次執(zhí)行時(shí)归粉,會(huì)將useState的參數(shù)初始化給count椿疗,而以后在執(zhí)行時(shí),則會(huì)直接取上次setCount(如果有調(diào)用)賦過的值(React通過某種方式保存起來的)糠悼。
有了這個(gè)概念届榄,就不難知道,定時(shí)器里的setCount(count + 1)倔喂,這個(gè) count 和每次更新重新聲明的 count铝条,也是完全不同的兩個(gè)常量,只不過它們的值席噩,可能會(huì)相等班缰。

比如,我們嘗試把之前的 num悼枢,直接用 count 替代埠忘。

function Counter() {
    // 注意這里變成 let
    let [count, setCount] = useState(0);
    useEffect(() => {
        const id = setInterval(() => {
            // 這種寫法是不好的
            setCount(++count);
        }, 1000);
    }, []);
    console.log(count);
    return <h1>{count}</h1>;
}

這時(shí)候不論是打印還是頁面表現(xiàn)都和你期望的一樣。
但這違背了React的原則馒索,而且也讓程序變得更加讓人迷惑莹妒。
也就導(dǎo)致了你并不能清楚的知道:此時(shí)渲染的count和set interval中的count已經(jīng)不是同一個(gè)了。盡管他們的值是相等的绰上。
當(dāng)然动羽,這種場景下react提供了可行的方法,能夠每次拿到count的最新值渔期,就是給setCount傳遞一個(gè)回調(diào)函數(shù)运吓。

function Counter() {
    const [count, setCount] = useState(0);
    useEffect(() => {
        const id = setInterval(() => {
            // 注意:這里變成回調(diào)了
            setCount(count => count + 1);
        }, 1000);
    }, []);

    return <h1>{count}</h1>;
}

執(zhí)行圖解

回過頭再看看開始的例子:

function Counter() {
    const [count, setCount] = useState(0);
    useEffect(() => {
        const id = setInterval(() => {
            setCount(count + 1);
        }, 1000);
    }, []);

    return <h1>{count}</h1>;
}
image

小結(jié):

count 每次都被重新聲明了,setInterval 因?yàn)?useEffect 設(shè)置了只執(zhí)行一次的緣故疯趟,在第一次更新時(shí)閉包引用的 count 始終是 0拘哨,后續(xù)更新的 count 和它沒關(guān)系。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末信峻,一起剝皮案震驚了整個(gè)濱河市倦青,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌盹舞,老刑警劉巖产镐,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件隘庄,死亡現(xiàn)場離奇詭異,居然都是意外死亡癣亚,警方通過查閱死者的電腦和手機(jī)丑掺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來述雾,“玉大人街州,你說我怎么就攤上這事〔C希” “怎么了唆缴?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長黍翎。 經(jīng)常有香客問我面徽,道長,這世上最難降的妖魔是什么匣掸? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任趟紊,我火速辦了婚禮,結(jié)果婚禮上旺聚,老公的妹妹穿的比我還像新娘织阳。我一直安慰自己眶蕉,他們只是感情好颤殴,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布联四。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪玖翅。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天各吨,我揣著相機(jī)與錄音叛甫,去河邊找鬼。 笑死谐丢,一個(gè)胖子當(dāng)著我的面吹牛爽航,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播乾忱,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼讥珍,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了窄瘟?” 一聲冷哼從身側(cè)響起衷佃,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蹄葱,沒想到半個(gè)月后氏义,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體锄列,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年惯悠,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了邻邮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡吮螺,死狀恐怖饶囚,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情鸠补,我是刑警寧澤萝风,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站紫岩,受9級(jí)特大地震影響规惰,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜泉蝌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一歇万、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧勋陪,春花似錦贪磺、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至违孝,卻和暖如春刹前,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背雌桑。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來泰國打工喇喉, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人校坑。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓拣技,卻偏偏與公主長得像,于是被迫代替她去往敵國和親耍目。 傳聞我的和親對(duì)象是個(gè)殘疾皇子膏斤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

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

  • Hook 是 React 16.8 的新增特性。它可以讓你在不編寫 class 的情況下使用 state 以及其他...
    konnga閱讀 32,843評(píng)論 0 6
  • React是現(xiàn)在最流行的前端框架之一制妄,它的輕量化掸绞,組件化,單向數(shù)據(jù)流等特性把前端引入了一個(gè)新的高度,現(xiàn)在它又引入的...
    老鼠AI大米_Java全棧閱讀 5,774評(píng)論 0 26
  • 你還在為該使用無狀態(tài)組件(Function)還是有狀態(tài)組件(Class)而煩惱嗎衔掸?——擁有了hooks烫幕,你再也不需...
    水落斜陽閱讀 82,316評(píng)論 11 100
  • 1、什么是react React.js 是一個(gè)幫助你構(gòu)建頁面 UI 的庫敞映。React.js 將幫助我們將界面分成了...
    谷子多閱讀 2,555評(píng)論 1 13
  • React 生命周期很多人都了解较曼,但通常我們所了解的都是單個(gè)組件的生命周期,但針對(duì)Hooks 組件振愿、多個(gè)關(guān)聯(lián)組件(...
    前端js閱讀 6,996評(píng)論 3 7