hook的使用總結(jié)

hook簡介

Hook 是 React 16.8 的新增特性。它可以讓你在不編寫 class 的情況下使用 state 以及其他的 React 特性。踐行函數(shù)式編程的方式,在函數(shù)組件中使用磨镶,獲得class編寫的特性。

useState和useReducer

useState

  • useState給一個(gè)state賦初始值,并且返回一個(gè)數(shù)組,一個(gè)用來讀取state的值,一個(gè)用來設(shè)置state的值咕娄。
  • useState聲明的state在發(fā)生變化的時(shí)候,會觸發(fā)組件的更新珊擂。
  • setState更新state是異步更新策略圣勒,參數(shù)有兩種,一種要更新的值未玻,第二種是一個(gè)更新的函數(shù),返回要更新的值胡控。
  • setState不會進(jìn)行合并更新扳剿,只會全量更新,所以參數(shù)或回調(diào)函數(shù)值應(yīng)該要更新的值昼激。
const [state, setState] = useState(10);
// 賦值修改
setState(20) // 此方法就是將state修改為20
// 函數(shù)修改
setState(current => {
    // current 是當(dāng)前state的值
    return current + 20; // 修改state的值為40
   // return state + 20; // 這樣也是可以的
})

useReducer

useState 的替代方案庇绽。它接收一個(gè)形如 (state, action) => newState 的 reducer,并返回當(dāng)前的 state 以及與其配套的 dispatch 方法橙困。(如果你熟悉 Redux 的話瞧掺,就已經(jīng)知道它如何工作了。)

用法簡介

const [state, dispatch] = useReducer(reducer, initialState, init);
  • reducer是一個(gè)函數(shù)凡傅,該函數(shù)接受兩個(gè)參數(shù)辟狈,一個(gè)是state一個(gè)是action, 是修改state值得函數(shù)。
  • initialState 初始值
  • init一個(gè)函數(shù)夏跷,用于初始化時(shí)調(diào)用的函數(shù)哼转,返回的就是初始化的state
  • useReducer返回一個(gè)狀態(tài)statedispatch槽华,state是返回狀態(tài)的值壹蔓,dispatch是可以發(fā)布事件來更新state的函數(shù),修改state值得韓式就是reducer猫态。

指定初始值

function counter = () => {
    // 聲明count佣蓉,返回一個(gè)count 和 dispatch
    const [count, dispatch] = useReducer((state, action) => {
        // state 就是當(dāng)前count的值
        // action 就是dispatch函數(shù)的參數(shù),可以為任何類型的數(shù)據(jù)
        if (action === 'add') {
            return state + 1;
        } else {
            return state - 1;
        }
    }, 0) // 默認(rèn)初始值為0

    return (
        <div>
            <h1>{count}</h1>
            {* 調(diào)用dispatch來更新count *}
            <button onClick={dispatch('sub')}> -1 </button>
            <button onClick={dispatch('sub')}> +1 </button>
        </div>
    )
}

惰性初始化

如果state初始化時(shí)需要有重置的操作或者state初始化的值十分復(fù)雜亲雪,都可以使用useReducer的第三個(gè)參數(shù)init

const initState = 10;
// 重置時(shí)會走該函數(shù)
const init = initState => {
    return initState;
}

function counter = () => {
    // 聲明count勇凭,返回一個(gè)count 和 dispatch
    const [count, dispatch] = useReducer((state, action) => {
        // state 就是當(dāng)前count的值
        // action 就是dispatch函數(shù)的參數(shù),可以為任何類型的數(shù)據(jù)
        if (action === 'add') {
            return state + 1;
        } else if(action === 'sub') {
            return state - 1;
        } else if (action === 'reset') {
            return init(initState);
        }
    }, initState, init)

    return (
        <div>
            <h1>{count}</h1>
            {* 調(diào)用dispatch來更新count *}
            <button onClick={dispatch('sub')}> -1 </button>
            <button onClick={dispatch('sub')}> +1 </button>
            <button onClick={dispatch('reset')}> 重置 </button>
        </div>
    )
}

注意

  • 當(dāng)useReducer返回的state和當(dāng)前的一樣時(shí)义辕,是不會重新渲染該組件的套像,因?yàn)閞eact使用Object.js來比較state。
  • 對于state有比較復(fù)雜的賦值操作時(shí)建議使用useReducer來聲明和處理终息。

useEffect 和 useLayoutEffect

useEffect

  • useEffect可以執(zhí)行副作用的操作
  • useEffect有兩個(gè)參數(shù)夺巩,一個(gè)回調(diào)函數(shù)贞让,一個(gè)數(shù)組類型變量(這里面的值必須是依賴項(xiàng),就是使用useState等聲明的變量柳譬,可以觸發(fā)組件更新的變量)
  • useEffect會在每次render的時(shí)候都執(zhí)行喳张,可以通過參數(shù)控制只在初始化時(shí)執(zhí)行、某些數(shù)據(jù)變化時(shí)執(zhí)行
  • 相當(dāng)于class組件的聲明周期componentDidMount(組件渲染后執(zhí)行)和componentDidUpdate(組件更新后執(zhí)行)
  • useEffect是一個(gè)回調(diào)函數(shù)美澳,如果返回一個(gè)函數(shù)時(shí)销部,則會在componentWillUnmount(組件銷毀)時(shí)執(zhí)行

只在初始化時(shí)執(zhí)行

在第二個(gè)參數(shù)中傳遞[]空數(shù)組,則只在初始化時(shí)調(diào)用

useEffect(() => {
    // 初始化時(shí)獲取list數(shù)據(jù)
    getList();
}, [])

在初始化和render更新時(shí)執(zhí)行

第二個(gè)參數(shù)不穿時(shí)制跟,會在初始化和更新時(shí)執(zhí)行

useEffect(() => {
    getList();
})

在某些數(shù)據(jù)變化時(shí)執(zhí)行

// 在count數(shù)據(jù)變化的時(shí)候執(zhí)行
useEffect(() => {
    getList();
}, [count]) // 數(shù)組中可以放許多的變量舅桩,在這些數(shù)據(jù)變化時(shí)都會執(zhí)行

useLayoutEffect

  • 當(dāng)需要處理dom時(shí),使用useEffect會導(dǎo)致閃屏問題
  • useLayoutEffect會在DOM更新完成后立即執(zhí)行雨膨,在瀏覽器進(jìn)行回執(zhí)之前運(yùn)行
  • 回阻塞瀏覽器的繪制

useContext

介紹

  • 接受一個(gè)context(React.createContext的返回值)對象
  • useContext幫助我們跨越組件層級直接傳遞變量擂涛,實(shí)現(xiàn)共享,解決了組件之間傳值的問題聊记。
  • context對象提供provider屬性將數(shù)據(jù)可以通過垮組件訪問撒妈,通過value將值傳給子組件
  • useContext獲取的數(shù)據(jù)是跟隨數(shù)據(jù)源里的數(shù)據(jù)的變化而變化的。
const value = useContext(MyContext);

使用

// 父組件 parent.js
import React, { useState, createContext } from 'react'
import Children from './children.js'

const Parent = () => {
    const [count, setCount] = useState(10);
    const CountContext = createContext();
    
    return (
        <>
            <CountContext.Provider value={{count}}>
                <Children countContext={CountContext}/>
            </CountContext.Provider>
            <h1>{ count }</h1>
            <button onClick={() => setCount(count + 1)}>
                加1
            </button>
        </>
    )
}

// 子組件 children.js
import React, { useContext } from 'react'

const Children = props => {
    // 這里的countContext是從組件傳遞過來的
    // 也可以把createCount單獨(dú)放到模塊里面進(jìn)行引用
    // 引用模式應(yīng)該比props好排监,可以適應(yīng)組件嵌套的問題
    const { countContext } = props;
    // 這里的數(shù)據(jù)是隨著父組件中的count數(shù)據(jù)變化而變化的
    const countData = useContext(countContext);
    
    return (
        <h1>{ countData.count }</h1>
    )
}

useRef 與 useImperativeHandle

useRef

const refContainer = useRef(initialValue);
  • useRef返回一個(gè)可變的ref對象狰右,其.current屬性就是被初始化傳入的參數(shù)。
  • useRef中的值發(fā)生變化不會觸發(fā)組件的更新
  • useRef可以用來保存任何可變值舆床。
  • 綁定到原生html上面可以獲取該標(biāo)簽的方法棋蚌,綁定到自定義組件上,則不要通過useImperativeHandle將部分方法和屬性暴露出來挨队。
  • useImperativeHandle可以在使用ref的時(shí)候自定義暴露給父組件的實(shí)例值和方法附鸽,需要和forwardRef一起使用

useImperativeHandle

useImperativeHandle(ref, createHandle, [deps])
  • ref:定義 current 對象的 ref createHandle:一個(gè)函數(shù),返回值是一個(gè)對象瞒瘸,即這個(gè) ref 的 current對象
  • [deps]:即依賴列表坷备,當(dāng)監(jiān)聽的依賴發(fā)生變,useImperativeHandle 才會重新將子組件的實(shí)例屬性輸出到父組件
  • ref 的 current 屬性上,如果為空數(shù)組情臭,則不會重新輸出省撑。

實(shí)例

// 父組件 parent.js
import React, {useRef} from 'react'
import Children from './children'

const Parent = () => {
    const childRef = useRef();
    
    return (
        <>
            <Children ref={childRef} />
            <button onClick={() => childRef.current.addCount()} >+1</button>
        </>
    )
}
// children.js
import React, {useState, useImperativeHandle, forwardRef} from 'react'

// 第二個(gè)參數(shù)才是ref,第一個(gè)是props
const Children = (props, ref) => {
    const [count, setCount] = useState(1)
    
    useImperativeHandle(ref, () => {
        addCount: setCount
    })
    
    return (
        <h1>{count}</h1>
    )
}

// 需要使用forwardRef進(jìn)行一次轉(zhuǎn)發(fā)
export default forwardRef(Children);

useCallback和useMemo

  • 都是用于數(shù)據(jù)緩存的方法
  • 都可以根據(jù)依賴項(xiàng)進(jìn)行刷新
  • 主要是用在不需要隨著組件更新而更新的情況時(shí)俯在,用于優(yōu)化部分復(fù)雜函數(shù)更新問題
  • useCallback返回函數(shù)竟秫,并不調(diào)用他們
  • useMemo 調(diào)用函數(shù),返回執(zhí)行的結(jié)果

用法

// useCallback 返回一個(gè)函數(shù)
const memoizedCallback = useCallback(
  () => {
    doSomething(a, b);
  },
  [a, b],
);
// useMemo  執(zhí)行函數(shù)跷乐,返回執(zhí)行的結(jié)果
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

例子

// parent.js
import React, {useState, useCallback, useMemo} from 'react'
import ChildrenComponent from './Children.js'

const Parent = () => {
    const [count, setCount] = useState(10)
    const [num, setNum] = useState(10)
    
    // 只有count變化的時(shí)候countName才會更新肥败,可以作為優(yōu)化部分
    const countName = useMemo(() => `年齡:${count}`, [count]);
    
    // 這樣,只有在num更新的時(shí)候,children組件才會更新
    const setDataNum = useCallback(() => setNum(num + 10), [num]);
    
    return (
        <div>
            <h1>
                {countName}
            </h1>
            <button onClick={() => setCount(count + 1)}>+1</button>
            <H1>NUM {num}</H1>
            <ChildrenComponent setData={setDataNum}/>
        </div>
    )
}

// children.js
import React from 'react';

const Children = ({setData}) => {
    return (
        <button onClick={() => setData()}>加10</button>
    )
}

export React.memo(Children)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末馒稍,一起剝皮案震驚了整個(gè)濱河市皿哨,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌纽谒,老刑警劉巖证膨,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異鼓黔,居然都是意外死亡央勒,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進(jìn)店門澳化,熙熙樓的掌柜王于貴愁眉苦臉地迎上來崔步,“玉大人,你說我怎么就攤上這事缎谷【簦” “怎么了?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵慎陵,是天一觀的道長眼虱。 經(jīng)常有香客問我喻奥,道長席纽,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任撞蚕,我火速辦了婚禮润梯,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘甥厦。我一直安慰自己纺铭,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布刀疙。 她就那樣靜靜地躺著舶赔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪谦秧。 梳的紋絲不亂的頭發(fā)上竟纳,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天,我揣著相機(jī)與錄音疚鲤,去河邊找鬼锥累。 笑死,一個(gè)胖子當(dāng)著我的面吹牛集歇,可吹牛的內(nèi)容都是我干的桶略。 我是一名探鬼主播,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼际歼!你這毒婦竟也來了惶翻?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤蹬挺,失蹤者是張志新(化名)和其女友劉穎维贺,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體巴帮,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡溯泣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了榕茧。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片垃沦。...
    茶點(diǎn)故事閱讀 39,727評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖用押,靈堂內(nèi)的尸體忽然破棺而出肢簿,到底是詐尸還是另有隱情,我是刑警寧澤蜻拨,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布池充,位于F島的核電站,受9級特大地震影響缎讼,放射性物質(zhì)發(fā)生泄漏收夸。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一血崭、第九天 我趴在偏房一處隱蔽的房頂上張望卧惜。 院中可真熱鬧,春花似錦夹纫、人聲如沸咽瓷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽茅姜。三九已至,卻和暖如春月匣,著一層夾襖步出監(jiān)牢的瞬間钻洒,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工桶错, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留航唆,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓院刁,卻偏偏與公主長得像糯钙,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,619評論 2 354

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

  • github的MD[https://github.com/liusanhong/study/blob/master...
    半個(gè)木頭人閱讀 276評論 0 0
  • 主要介紹 useState useEffect useReducer useContext 用法 你還在為...
    叫我蘇軾好嗎閱讀 27,410評論 3 41
  • 什么是React Hook? 一個(gè)特殊的函數(shù)任岸,用于鉤入React的特性再榄。它鼓勵我們將通用邏輯封裝成Hook而不是工...
    南山碼僧閱讀 621評論 0 7
  • Hook 是 react 16.8 推出的新特性,具有如下優(yōu)點(diǎn):Hook 使你在無需修改組件結(jié)構(gòu)的情況下復(fù)用狀態(tài)邏...
    林木木road閱讀 789評論 0 1
  • 一享潜、組件類 React的核心是組件, 在v16.8之前,組件的標(biāo)準(zhǔn)寫法是類(class)困鸥。 以下為一個(gè)簡單的組件類...
    郭_小青閱讀 708評論 1 5