1. 程式人生 > 其它 >React hooks解析(useState() useEffect() userReducer() useCallback() useMemo())

React hooks解析(useState() useEffect() userReducer() useCallback() useMemo())

什麼是Hooks?

'Hooks'的單詞意思為“鉤子”。React Hooks 的意思是,元件儘量寫成純函式,如果需要外部功能和副作用,就用鉤子把外部程式碼"鉤"進來。而React Hooks 就是我們所說的“鉤子”。

常用的鉤子

useState()
useEffect()
userReducer()
useCallback()
useMemo()
useRef()

一、userState():狀態鉤子

純函式元件沒有狀態,useState()用於為函式元件引入狀態。在useState()中,陣列第一項為一個變數,指向狀態的當前值。類似this.state,第二項是一個函式,用來更新狀態,類似setState。

import React, {useState} from 'react'
const AddCount = () => {
  const [ count, setCount ] = useState(0)
  return (
    <div>
      <button onClick={setCount(count++)}>加一</button>
    </>
  )
}
export default AddCount 

二、useEffect():副作用鉤子

useEffect()接受兩個引數,第一個引數是你要進行的非同步操作,第二個引數是一個數組,用來給出Effect的依賴項。只要這個陣列發生變化,useEffect

()就會執行

useEffect()可以看做componentDidMountcomponentDidUpdatecomponentWillUnmount這三個函式的組合。

useEffect(
  () => { 
    const subscription = props.source.subscribe();
    return () => {//相當於ComponentWillUnmount
      subscription.unsubscribe();
    };
  },
  [props.source],//相當於ComponentDidUpdate
);

三、useReducer():Action鉤子

我們通過使用者在頁面中發起action,從而通過reducer方法來改變state,從而實現頁面和狀態的通訊。
const [state, dispatch] = useReducer(reducer, initialState)

它接受reducer函式和狀態的初始值作為引數,返回一個數組,其中第一項為當前的狀態值,第二項為傳送action的dispatch函式。下面我們依然用來實現一個計數器。

const reduer = (state, action) => {
    switch(action) {
        case 'add': return state + 1;
        case 'reduce': return state - 1;
        case 'reset': return 0;
        default:return state;
  }
}

函式元件:

import React,{useReducer} from 'react'
export default function Counter() {
     const [counter, dispatch] = useReducer(reduer, 0);
}
return (
    <div >
          <div>{counter}</div>
          <Button onClick={() => dispatch('add')}>遞增</Button>
          <Button onClick={() => dispatch('reduce')}>遞減</Button>
          <Button onClick={() => dispatch('reset')}>重置</Button>
    </div>
  );
}

useState是useReducer的一個子集,useState 返回的函式內部封裝了一個 dispatch。useReducer( 單個元件中用的少,太重了)

官方的定義:在某些場景下,useReducer會比useState更適用,例如 state 邏輯較複雜且包含多個子值(注意且字),或者下一個 state 依賴於之前的 state 等。

四、useCallback和useMemo

useMemo 和 useCallback 接收的引數都是一樣,第一個引數為回撥,第二個引數為要依賴的資料

共同作用:僅僅依賴資料發生變化, 才會呼叫,也就是起到快取的作用。useCallback快取函式,useMemo 快取返回值。

useCallback使用場景是:有一個父元件,其中包含子元件,子元件接收一個函式作為props;通常而言,如果父元件更新了,子元件也會執行更新;所有依賴本地狀態或props來建立函式,需要使用到快取函式的地方,都是useCallback的應用場景。

父元件:

import React, { useCallback } from 'react'

function ParentComp () {
  // ...
  const [ name, setName ] = useState('hi~')
  // 每次父元件渲染,返回的是同一個函式引用
  const changeName = useCallback((newName) => setName(newName), [])  
  return (
    <div>
      <button onClick={increment}>點選次數:{count}</button>
      <ChildComp name={name} onClick={changeName}/>
    </div>
  );
}

子元件

import React, { memo } from 'react'

const ChildComp = memo(function ({ name, onClick }) {
  console.log('render child-comp ...')
  return <>
    <div>Child Comp ... {name}</div>
    <button onClick={() => onClick('hello')}>改變 name 值</button>
  </>
})

點選父元件按鈕,控制檯不會列印子元件被渲染的資訊了。

究其原因:useCallback() 起到了快取的作用,即便父元件渲染了,useCallback() 包裹的函式也不會重新生成,會返回上一次的函式引用。

useMemo

import React, { useCallback } from 'react'

function ParentComp () {
  // ...
  const [ name, setName ] = useState('hi~')
  const [ age, setAge ] = useState(20)
  const changeName = useCallback((newName) => setName(newName), [])
  const info = { name, age }    // 複雜資料型別屬性

  return (
    <div>
      <button onClick={increment}>點選次數:{count}</button>
      <ChildComp info={info} onClick={changeName}/>
    </div>
  );
}

父元件渲染,const info = { name, age }一行會重新生成一個新物件,導致傳遞給子元件的 info 屬性值變化,進而導致子元件重新渲染。

function ParentComp () {
  // ....
  const [ name, setName ] = useState('hi~')
  const [ age, setAge ] = useState(20)
  const changeName = useCallback((newName) => setName(newName), [])
  const info = useMemo(() => ({ name, age }), [name, age])   // 包一層

  return (
    <div>
      <button onClick={increment}>點選次數:{count}</button>
      <ChildComp info={info} onClick={changeName}/>
    </div>
  );
}

點選父元件按鈕,控制檯中不再列印子元件被渲染的資訊了。

參考:

https://www.jianshu.com/p/d600f749bb19

https://www.jianshu.com/p/014ee0ebe959