欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

30分鐘帶你全面了解React Hooks

 更新時(shí)間:2021年05月15日 09:39:17   作者:lovin  
Hooks是一種函數(shù),該函數(shù)允許您從函數(shù)式組件 “勾住(hook into)”React狀態(tài)和生命周期功能。Hooks在類內(nèi)部不起作用 - 它們?cè)试S你無(wú)需類就使用 React。

概述

1. Hooks 只能在函數(shù)組件內(nèi)使用;

2. Hooks 用于擴(kuò)充函數(shù)組件的功能,使函數(shù)組件可以完全代替類組件

React Hooks 都掛在 React 對(duì)象上,因此使用時(shí)為 React.useState() 的形式,若嫌麻煩,可以提前導(dǎo)入,如下:

import React, { useState } from "react"

React 內(nèi)置的 Hooks 有很多,這里介紹一些常用到的。全部的請(qǐng)看 Hooks API

用到了 Hook 的函數(shù)組件名必須首字母大寫,否則會(huì)被 ESLint 報(bào)錯(cuò)

1. useState

const [state, setState] = useState(initialState)

1.1 概念三連問

調(diào)用 useState 有什么作用?

useState 是用于聲明一個(gè)狀態(tài)變量的,用于為函數(shù)組件引入狀態(tài)。

我們傳遞給 useState 的參數(shù)是什么?

useState 只接收一個(gè)參數(shù),這個(gè)參數(shù)可以是數(shù)字、字符串、對(duì)象等任意值,用于初始化聲明的狀態(tài)變量。也可以是一個(gè)返回初始值的函數(shù),最好是函數(shù),可在渲染時(shí)減少不必要的計(jì)算。

useState返回的是什么?

它返回一個(gè)長(zhǎng)度為2的讀寫數(shù)組,數(shù)組的第一項(xiàng)是定義的狀態(tài)變量本身,第二項(xiàng)是一個(gè)用來(lái)更新該狀態(tài)變量的函數(shù),約定是 set 前綴加上狀態(tài)的變量名。如 setState,setState() 函數(shù)接收一個(gè)參數(shù),該參數(shù)可以是更新后的具體值,也可以是一個(gè)返回更新后具體值的函數(shù)。若 setState 接收的是一個(gè)函數(shù),則會(huì)將舊的狀態(tài)值作為參數(shù)傳遞給接收的函數(shù)然后得到一個(gè)更新后的具體狀態(tài)值。

1.2 舉個(gè)例子

function App(){
  const [n, setN] = useState(0)
  const [m, setM] = useState(() => 0)
  return (
    <div>
      n: {n}
      <button onClick={() => setN(n+1)}>+1</button>
      <br/>
      m: {m}
      <button onClick={() => setM(oldM => oldM+1)}>+1</button>
    </div>
  )
}

1.3 注意事項(xiàng)

  • useState Hook 中返回的 setState 并不會(huì)幫我們自動(dòng)合并對(duì)象狀態(tài)的屬性
  • setState 中接收的對(duì)象參數(shù)如果地址沒變的話會(huì)被 React 認(rèn)為沒有改變,因此不會(huì)引起視圖的更新

2. useReducer

useReducer 是 useState 的升級(jí)版。在 useState 中返回的寫接口中,我們只能傳遞最終的結(jié)果,在 setN 的內(nèi)部也只是簡(jiǎn)單的賦值操作。
也就是說(shuō),得到結(jié)果的計(jì)算過(guò)程需要我們?cè)诤瘮?shù)組件內(nèi)的回調(diào)函數(shù)中書寫,這無(wú)疑增加了函數(shù)組件的體積,而且也不符合 Flux 的思想(狀態(tài)由誰(shuí)產(chǎn)生的,誰(shuí)負(fù)責(zé)進(jìn)行各種處理,并暴露處理接口出去給別人用)

因此,React 就提供了比 useState 更高級(jí)的狀態(tài)管理 Hook:useReducer,介紹如下:

2.1 使用方法

  • 創(chuàng)建初始狀態(tài)值 initialState
  • 創(chuàng)建包含所有操作的 reducer(state, action) 函數(shù),每種操作類型均返回新的 state 值
  • 根據(jù) initialState 和 reducer 使用 const [state, dispatch] = useReducer(reducer, initialState) 得到讀寫 API
  • 調(diào)用寫接口,傳遞的參數(shù)均掛在 action 對(duì)象上

2.2 舉個(gè)例子

import React, { useReducer } from 'react';
import ReactDOM from 'react-dom';

const initialState = {
  n: 0
}

const reducer = (state, action) => {
  switch(action.type){
    case 'addOne':
      return { n: state.n + 1 }
    case 'addTwo':
      return { n: state.n + 2 }
    case 'addX':
      return { n: state.n + action.x }
    default: {
      throw new Error('unknown type')
    }
  }
}

function App(){
  const [state, dispatch] = useReducer(reducer, initialState)
  return (
    <div>
      我是 App
      {state.n}
      <button onClick={()=>dispatch({type: 'addOne'})}>+1</button>
      <button onClick={()=>dispatch({type: 'addTwo'})}>+2</button>
      <button onClick={()=>dispatch({type: 'addX', x: 5})}>+5</button>
    </div>
  )
}


ReactDOM.render(<App/>,document.getElementById('root'));

3. useContext

context 是上下文的意思,上下文是局部的全局變量這個(gè)局部的范圍由開發(fā)者自己指定。

3.1 使用方法

useContext 的使用方法分三步走:

  • 使用 const x = createContext(null) 創(chuàng)建上下文,在創(chuàng)建時(shí)一般不設(shè)置初始值,因此為 null,一般是在指定上下文作用域時(shí)初始化。
  • 使用 <x.Provider value={}></x.Provider> 圈定上下文的作用域
  • 在作用域中使用 const value = useContext(x) 使用上下文的數(shù)據(jù)

3.2 舉個(gè)例子

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

const Context = createContext(null)

function App(){
  const [n, setN] = useState(0)
  return (
    <Context.Provider value={{n, setN}}>
      <div>
        <Baba />
        <Uncle />
      </div>
    </Context.Provider>
  )
}

function Baba(){
  return (
    <div>
      我是爸爸
      <Child />
    </div>
  )
}

function Uncle(){
  const {n, setN} = useContext(Context)
  return (
    <div>
      我是叔叔
      我拿到的 context 數(shù)據(jù)為 {n}
    </div>
  )
}

function Child(){
  const {n, setN} = useContext(Context)
  return (
    <div>
      我是兒子
      我拿到的 context 數(shù)據(jù)為 {n}
      <button onClick={() => setN(n+5)}>
        點(diǎn)擊改變 context 數(shù)據(jù)
      </button>
    </div>
  )
}


ReactDOM.render(<App/>,document.getElementById('root'));

4. useEffect

effect 是副作用的意思,對(duì)環(huán)境的改變就是副作用。副作用好像是函數(shù)式編程里的一個(gè)概念,這里不做過(guò)多解讀,也不太懂。
在 React 中,useEffect 就是在每次 render 后執(zhí)行的操作,相當(dāng)于 afterRender, 接收的第一個(gè)參數(shù)是回調(diào)函數(shù),第二個(gè)參數(shù)是回調(diào)時(shí)機(jī)??捎迷诤瘮?shù)組件中模擬生命周期。

如果同時(shí)出現(xiàn)多個(gè) useEffect ,會(huì)按出現(xiàn)順序依次執(zhí)行

4.1 模擬 componentDidMount

useEffect(()=>{
  console.log('只在第一次 render 后執(zhí)行')
},[])

4.2 模擬 componentDidMount + componentDidUpdate

useEffect(()=>{
   console.log('每次 render 后都執(zhí)行,包括第一次 render')
})

4.3 可添加依賴

useEffect(()=>{
    console.log('只在 x 改變后執(zhí)行,包括第一次 x 從 undefined 變成 initialValue')
},[x])
//如果有兩個(gè)依賴,則是當(dāng)兩個(gè)依賴中的任何一個(gè)變化了都會(huì)執(zhí)行

4.4 模擬 componentWillUnmount

useEffect(()=>{
  console.log('每次 render 后都執(zhí)行,包括第一次 render')
  return ()=>{
    console.log('該組件要被銷毀了')
  }
})
//直接 return 一個(gè)函數(shù)即可,該函數(shù)會(huì)在組件銷毀前執(zhí)行

5. useLayoutEffect

useEffect 總是在瀏覽器渲染完視圖過(guò)后才執(zhí)行,如果 useEffect 里面的回調(diào)函數(shù)有對(duì) DOM 視圖的操作,則會(huì)出現(xiàn)一開始是初始化的視圖,后來(lái)執(zhí)行了 useEffect 里的回調(diào)后立馬改變了視圖的某一部分,會(huì)出現(xiàn)一個(gè)閃爍的狀態(tài)。
為了避免這種閃爍,可以將副作用的回調(diào)函數(shù)提前到瀏覽器渲染視圖的前面執(zhí)行,當(dāng)還沒有將 DOM 掛載到頁(yè)面顯示前執(zhí)行 Effect 中對(duì) DOM 進(jìn)行操作的回調(diào)函數(shù),則在瀏覽器渲染到頁(yè)面后不會(huì)出現(xiàn)閃爍的狀態(tài)。

layout 是視圖的意思,useLayoutEffect 就是在視圖顯示出來(lái)前執(zhí)行的副作用。

useEffect 和 useLayoutEffect 就是執(zhí)行的時(shí)間點(diǎn)不同,useLayoutEffect 是在瀏覽器渲染前執(zhí)行,useEffect 是在瀏覽器渲染后執(zhí)行。但二者都是在 render 函數(shù)執(zhí)行過(guò)程中運(yùn)行,useEffect 是在 render 完畢后執(zhí)行,useLayoutEffect 是在 render 完畢前(視圖還沒渲染到瀏覽器頁(yè)面上)執(zhí)行。

因此 useLayoutEffect 總是在 useEffect 前執(zhí)行。

一般情況下,如果 Effect 中的回調(diào)函數(shù)中涉及到 DOM 視圖的改變,就應(yīng)該用 useLayoutEffect,如果沒有,則用 useEffect。

6. useRef

useRef Hook 是用來(lái)定義一個(gè)在組件不斷 render 時(shí)保持不變的變量。
組件每次 render 后都會(huì)返回一個(gè)虛擬 DOM,組件內(nèi)對(duì)應(yīng)的變量都只屬于那個(gè)時(shí)刻的虛擬 DOM。
useRef Hook 就提供了創(chuàng)建貫穿整個(gè)虛擬 DOM 更新歷史的屬于這個(gè)組件的局部的全局變量。
為了確保每次 render 后使用 useRef 獲得的變量都能是之前的同一個(gè)變量,只能使用引用做到,因此,useRef 就將這個(gè)局部的全局變量的值存儲(chǔ)到了一個(gè)對(duì)象中,屬性名為:current

useRef 的 current 變化時(shí)不會(huì)自動(dòng) render

useRef 可以將創(chuàng)建的 Refs 對(duì)象通過(guò) ref 屬性的方式引用到 DOM 節(jié)點(diǎn)或者 React 實(shí)例。這個(gè)作用在 React—ref 屬性 中有介紹。

同樣也可以作為組件的局部的全局變量使用,如下例的記錄當(dāng)前是第幾次渲染頁(yè)面。

function App(){
  const [state, dispatch] = useReducer(reducer, initialState)
  const count = useRef(0)
  useEffect(()=>{
    count.current++;
    console.log(`這是第 ${count.current} 次渲染頁(yè)面`)
  })
  return (
    <div>
      我是 App
      {state.n}
      <button onClick={()=>dispatch({type: 'addOne'})}>+1</button>
      <button onClick={()=>dispatch({type: 'addTwo'})}>+2</button>
      <button onClick={()=>dispatch({type: 'addX', x: 5})}>+5</button>
    </div>
  )
}

7. forwardRef(不是 Hook)

forwardRef 主要是用來(lái)對(duì)原生的不支持 ref屬性 函數(shù)組件進(jìn)行包裝使之可以接收 ref屬性 的,具體使用方法可參考 React—ref 屬性

forwardRef 接收一個(gè)函數(shù)組件,返回一個(gè)可以接收 ref 屬性的函數(shù)組件

8. useMemo && useCallback

React 框架是通過(guò)不斷地 render 來(lái)得到不同的虛擬 DOM ,然后進(jìn)行 DOM Diff 來(lái)進(jìn)行頁(yè)面 DOM 的選擇性更新的,因此,在每次的 render 之后都會(huì)短時(shí)間內(nèi)存在新舊兩個(gè)虛擬 DOM 。

對(duì)于組件內(nèi)包含子組件的情況,當(dāng)父組件內(nèi)觸發(fā) render 時(shí),就算子組件依賴的 props 沒有變化,子組件也會(huì)因?yàn)楦附M件的重新 render 再次 render 一遍。這樣就產(chǎn)生了不必要的 render 。

為了解決不必要的 render ,React 提供了 React.memo() 接口來(lái)對(duì)子組件進(jìn)行封裝。如下:

function App(){
  const [n, setN] = useState(0)
  const [m, setM] = useState(0)
  return (
    <div>
      我是父組件
      n: {n}
      <button onClick={()=>setN(n+1)}>n+1</button>
      <button onClick={()=>setM(m+1)}>m+1</button>
      <Child value={m}/>  //這樣當(dāng)子組件依賴的 m 值沒有變化時(shí),子組件就不會(huì)重新 render
    </div>
  )
}

const Child = React.memo((props)=>{
  useEffect(()=>{
    console.log('子組件 render 了')
  })
  return (
  <div>我是子組件,我收到來(lái)自父組件的值為:m {props.value}</div>
  )
})

但是上述方式存在 bug,因?yàn)?React.memo 在判斷子組件依賴的屬性有沒有發(fā)生改變時(shí)僅僅是做的前后值是否相等的比較,如果子組件從父組件處接收的依賴是一個(gè)對(duì)象的話,比較的就會(huì)是對(duì)象的地址,而不是對(duì)象里面的內(nèi)容,因此在每次父組件重新 render 后得到的會(huì)是不同地址的對(duì)象,盡管對(duì)象里面的值沒有更新,但是子組件發(fā)現(xiàn)地址變了也會(huì)重新 render。

為了解決這個(gè)問題,就又出來(lái)了 useMemo() Hook,useMemo 是用于在新舊組件交替時(shí)緩存復(fù)用一個(gè)函數(shù)或者一個(gè)對(duì)象,當(dāng)某個(gè)依賴重新變化時(shí)才重新生成。

useMemo Hook 接收一個(gè)無(wú)參數(shù)的返回函數(shù)(或?qū)ο螅┑暮瘮?shù)。并且 useMemo 必須有個(gè)依賴,告訴其在什么時(shí)候重新計(jì)算。有點(diǎn)類似于 Vue 的計(jì)算屬性的原理。如下:

function App(){
  const [n, setN] = useState(0)
  const [m, setM] = useState(0)
  const onClickChild = useMemo(()=>{
    return () => {
      console.log(m)
    }
  },[m])  
  return (
    <div>
      我是父組件
      n: {n}
      <button onClick={()=>setN(n+1)}>n+1</button>
      <button onClick={()=>setM(m+1)}>m+1</button>
      <Child value={m} onClick = {onClickChild}/>
    </div>
  )
}

const Child = React.memo((props)=>{
  useEffect(()=>{
    console.log('子組件 render 了')
  })
  return (
    <div>
      我是子組件,我收到來(lái)自父組件的值為:m {props.value}
      <br/>
      <button onClick={props.onClick}>click</button>
    </div>
  )
})

useCallback() 是 useMemo 的語(yǔ)法糖,因?yàn)?useMemo 是接收一個(gè)沒有參數(shù)的返回函數(shù)(或?qū)ο螅┑暮瘮?shù),會(huì)有些奇怪,因此提供了 useCallback 來(lái)直接接收函數(shù)或?qū)ο蟆?/p>

const onClickChild = useMemo(() => {
      console.log(m)
  },[m])

9. useInperativeHandle

useInperativeHandel 是和 ref 相關(guān)的一個(gè) Hook。

我們知道,ref 屬性是會(huì)將當(dāng)前的組件實(shí)例或 原生DOM 直接賦值給傳入的 Ref 對(duì)象的 current 屬性上,而且函數(shù)組件不能接收 ref 屬性,因?yàn)楹瘮?shù)組件沒有實(shí)例。但是如果函數(shù)組件經(jīng)過(guò) React.forwardRef() 封裝過(guò)后 可以接收 ref,一般情況下,這個(gè) ref 是訪問的經(jīng)過(guò)函數(shù)組件轉(zhuǎn)發(fā)過(guò)后的 原生DOM,但是,如果在函數(shù)組件內(nèi)不僅僅是想讓外來(lái)的 ref 指向一個(gè) 原生DOM 呢?可不可以讓函數(shù)組件的 ref 像類組件中的 ref 指向?qū)嵗粯訐碛懈嗟目煽匦圆僮髂??React 就為函數(shù)組件提供了一種封裝返回的 ref 指向的對(duì)象的方法,就是 useInperativeHandle Hook。

9.1 舉個(gè)例子

function App(){
  const myRef = useRef(null)
  useEffect(()=>{
    console.log(myRef.current.real)
    console.log(myRef.current.getParent())
  }, [])
  return (
    <div>
      我是父組件
      <Child ref={myRef}/>
    </div>
  )
}

const Child = forwardRef((props, ref)=>{
  const childRef = useRef(null)
  useImperativeHandle(ref, ()=>{
    return {
      real: childRef.current,
      getParent(){
        return childRef.current.parentNode
      }
    }
  })
  return (
    <div>
      我是子組件,我有一個(gè)子DOM
      <button ref={childRef}>按鈕</button>
    </div>
  )
})

10. 自定義 Hook

自定義 Hook 就是自定義一個(gè)函數(shù),這個(gè)函數(shù)必須以 use 開頭,并且,該函數(shù)里必須用到原生的 Ract Hooks,返回值一般是一個(gè)數(shù)組或一個(gè)對(duì)象,用于暴露該 Hooks 的讀寫接口。

自定義 Hook 通常是將函數(shù)組件中多次用到的 hook 整合到一起,盡量在函數(shù)組件中不要出現(xiàn)多次 hook 操作。

以上就是30分鐘帶你全面了解React Hooks的詳細(xì)內(nèi)容,更多關(guān)于全面了解React Hooks的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 一文帶你搞懂useCallback的使用方法

    一文帶你搞懂useCallback的使用方法

    useCallback是用來(lái)幫忙緩存函數(shù)的,當(dāng)依賴項(xiàng)沒有發(fā)生變化時(shí),返回緩存的指針,而props涉及到復(fù)雜對(duì)象類型都是通過(guò)指針來(lái)傳遞到,下面這篇文章主要給大家介紹了關(guān)于useCallback使用的相關(guān)資料,需要的朋友可以參考下
    2023-02-02
  • Parcel 打包示例(React HelloWorld)

    Parcel 打包示例(React HelloWorld)

    本篇文章主要介紹了Parcel 打包示例(React HelloWorld),詳細(xì)的介紹了Parcel打包的特點(diǎn)和使用示例,有興趣的可以了解一下
    2018-01-01
  • 實(shí)現(xiàn)React單頁(yè)應(yīng)用的方法詳解

    實(shí)現(xiàn)React單頁(yè)應(yīng)用的方法詳解

    今天我們來(lái)學(xué)習(xí)React是如何構(gòu)建起一個(gè)單頁(yè)應(yīng)用的,React作為目前最流行的前端框架之一,其受歡迎程度不容小覷,從這門框架上我們可以學(xué)到許多其他前端框架所缺失的東西,也是其創(chuàng)新性所在的地方,比如虛擬DOM、JSX等。下面一起來(lái)看看。
    2016-08-08
  • react中實(shí)現(xiàn)將一個(gè)視頻流為m3u8格式的轉(zhuǎn)換

    react中實(shí)現(xiàn)將一個(gè)視頻流為m3u8格式的轉(zhuǎn)換

    這篇文章主要介紹了react中實(shí)現(xiàn)將一個(gè)視頻流為m3u8格式的轉(zhuǎn)換方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • React如何立即更新DOM

    React如何立即更新DOM

    這篇文章主要介紹了React如何立即更新DOM問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • React中父組件如何獲取子組件的值或方法

    React中父組件如何獲取子組件的值或方法

    這篇文章主要介紹了React中父組件如何獲取子組件的值或方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • react中用less的問題

    react中用less的問題

    本文主要介紹了react中用less的問題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-04-04
  • 關(guān)于getDerivedStateFromProps填坑記錄

    關(guān)于getDerivedStateFromProps填坑記錄

    這篇文章主要介紹了關(guān)于getDerivedStateFromProps填坑記錄,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • 基于webpack開發(fā)react-cli的詳細(xì)步驟

    基于webpack開發(fā)react-cli的詳細(xì)步驟

    這篇文章主要介紹了基于webpack開發(fā)react-cli的詳細(xì)步驟,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-06-06
  • 詳解React Native 采用Fetch方式發(fā)送跨域POST請(qǐng)求

    詳解React Native 采用Fetch方式發(fā)送跨域POST請(qǐng)求

    這篇文章主要介紹了詳解React Native 采用Fetch方式發(fā)送跨域POST請(qǐng)求,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-11-11

最新評(píng)論