hook的使用總結(jié)

hook簡(jiǎn)介

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í)候,會(huì)觸發(fā)組件的更新。
  • setState更新state是異步更新策略,參數(shù)有兩種,一種要更新的值,第二種是一個(gè)更新的函數(shù),返回要更新的值。
  • setState不會(huì)進(jìn)行合并更新,只會(huì)全量更新,所以參數(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)知道它如何工作了。)

用法簡(jiǎn)介

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í)會(huì)走該函數(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í),是不會(huì)重新渲染該組件的,因?yàn)閞eact使用Object.js來比較state。
  • 對(duì)于state有比較復(fù)雜的賦值操作時(shí)建議使用useReducer來聲明和處理。

useEffect 和 useLayoutEffect

useEffect

  • useEffect可以執(zhí)行副作用的操作
  • useEffect有兩個(gè)參數(shù),一個(gè)回調(diào)函數(shù),一個(gè)數(shù)組類型變量(這里面的值必須是依賴項(xiàng),就是使用useState等聲明的變量,可以觸發(fā)組件更新的變量)
  • useEffect會(huì)在每次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í),則會(huì)在componentWillUnmount(組件銷毀)時(shí)執(zhí)行

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

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

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

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

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

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

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

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

useLayoutEffect

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

useContext

介紹

  • 接受一個(gè)context(React.createContext的返回值)對(duì)象
  • useContext幫助我們跨越組件層級(jí)直接傳遞變量,實(shí)現(xiàn)共享,解決了組件之間傳值的問題。
  • context對(duì)象提供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對(duì)象,其.current屬性就是被初始化傳入的參數(shù)。
  • useRef中的值發(fā)生變化不會(huì)觸發(fā)組件的更新
  • useRef可以用來保存任何可變值。
  • 綁定到原生html上面可以獲取該標(biāo)簽的方法,綁定到自定義組件上,則不要通過useImperativeHandle將部分方法和屬性暴露出來。
  • useImperativeHandle可以在使用ref的時(shí)候自定義暴露給父組件的實(shí)例值和方法,需要和forwardRef一起使用

useImperativeHandle

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

實(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才會(huì)更新,可以作為優(yōu)化部分
    const countName = useMemo(() => `年齡:${count}`, [count]);
    
    // 這樣,只有在num更新的時(shí)候,children組件才會(huì)更新
    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)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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

友情鏈接更多精彩內(nèi)容