React-Hook的使用

函數(shù)式組件在不編寫class的情況下使用state以及其他的React特性(比如生命周期)

一、Hooks結(jié)合函數(shù)式組件使用(useState)

通過一個(gè)計(jì)數(shù)器案例,來對(duì)比一下class組件和函數(shù)式組件結(jié)合hooks的對(duì)比:
1、class組件實(shí)現(xiàn):

import React, { PureComponent } from 'react';

class HookTest extends PureComponent {

  constructor(props){
    super(props)

    this.state = {
      count: 0
    }
    this.addCount = this.addCount.bind(this)
  }
  
  render() {
    return (
      <div>
        <h2>{this.state.count}</h2>
        <button onClick={this.addCount}>增加</button>
      </div>
    );
  }

  addCount(){
    this.setState({
      count: this.state.count+1
    })
  }
}

export default HookTest;

2、函數(shù)式組件結(jié)合hooks使用:

import React, { useState } from 'react';

function HookTest(){

 const [count, setCount] = useState(0)   // ES6結(jié)構(gòu)

  return (
    <div>
      <h2>{count}</h2>
      <button onClick={()=>setCount(count+2)}>增加</button>
    </div>
  )
}

export default HookTest

通過上面對(duì)比發(fā)現(xiàn),函數(shù)式組件結(jié)合hooks使用讓代碼看起來更加整齊。
解析:const [count, setCount] = useState(0)
1、其中count是參數(shù),setCount是設(shè)置參數(shù)count的函數(shù);
2、useState是一個(gè)函數(shù),返回一個(gè)數(shù)組,可結(jié)構(gòu)成一個(gè)參數(shù)和設(shè)置參數(shù)的函數(shù),有一個(gè)唯一的參數(shù),設(shè)置的是參數(shù)count的初始值。

3、在一個(gè)函數(shù)組件中定義多個(gè)變量和復(fù)雜變量(數(shù)組、對(duì)象):

import React, { useState } from 'react';

function HookTest(){

  const [count, setCount]     = useState(0)   // ES6結(jié)構(gòu)
  const [list, setList]       = useState(['A', 'B', 'C'])
  const [person, setPerson]   = useState({'name': 'Jack'})

  return (
    <div>
      <h2>{count}</h2>
      <h2>{person.name}-{person.age}</h2>
      <ul>
        {
          list.map((item, index) => {
            return (
              <li key={index}>{item}</li>
            )
          })
        }
      </ul>
      <button onClick={()=>setCount(count+2)}>增加數(shù)字</button>
      <button onClick={()=>setList([...list, 'D'])}>修改列表</button>
      <button onClick={()=>setPerson({...person, name: 'Lucy', age: 19})}>修改對(duì)象</button>
    </div>
  )
}

export default HookTest

二、 Effect Hook的使用(useEffect)

1、Effect Hook 類似于class中生命周期的功能

function Index(){

  // useEffect頁面初始化使用,相當(dāng)于componentDidMount
  useEffect(() => {
    console.log('index in');

    // return在頁面銷毀時(shí)候調(diào)用,相當(dāng)于componentWillUnmount
    return ()=>{
      console.log('index out'); 
    }
  }, [])
  return <h2>index page</h2>
}

2、使用多個(gè)Effect
使用Hook的其中一個(gè)目的就是解決class中生命周期經(jīng)常將很多的邏輯放在一起的問題:
比如網(wǎng)絡(luò)請(qǐng)求、事件監(jiān)聽、手動(dòng)修改DOM,這些往往都會(huì)放在componentDidMount中;
使用Effect Hook,我們可以將它們分離到不同的useEffect中:

import React, { useEffect } from 'react';

export default function MultiUseEffect() {
 useEffect(() => {
   console.log("網(wǎng)絡(luò)請(qǐng)求");
 });

 useEffect(() => {
   console.log("修改DOM");
 })

 useEffect(() => {
   console.log("事件監(jiān)聽");

   return () => {
     console.log("取消監(jiān)聽");
   }
 })

 return (
   <div>
     <h2>MultiUseEffect</h2>
   </div>
 )
}

Hook 允許我們按照代碼的用途分離它們, 而不是像生命周期函數(shù)那樣:
React 將按照 effect 聲明的順序依次調(diào)用組件中的每一個(gè) effect;

3、 Effect性能優(yōu)化
默認(rèn)情況下,useEffect的回調(diào)函數(shù)會(huì)在每次渲染時(shí)都重新執(zhí)行,但是這會(huì)導(dǎo)致兩個(gè)問題:
某些代碼我們只是希望執(zhí)行一次即可,類似于componentDidMount和componentWillUnmount中完成的事情;(比如網(wǎng)絡(luò)請(qǐng)求、訂閱和取消訂閱);
另外,多次執(zhí)行也會(huì)導(dǎo)致一定的性能問題;
我們?nèi)绾螞Q定useEffect在什么時(shí)候應(yīng)該執(zhí)行和什么時(shí)候不應(yīng)該執(zhí)行呢?
useEffect實(shí)際上有兩個(gè)參數(shù):
參數(shù)一:執(zhí)行的回調(diào)函數(shù);
參數(shù)二:該useEffect在哪些state發(fā)生變化時(shí),才重新執(zhí)行;(受誰的影響)
我們來看下面的一個(gè)案例:
在這個(gè)案例中,我們修改show的值,是不會(huì)讓useEffect重新被執(zhí)行的;

import React, { useState, useEffect } from 'react';

export default function EffectPerformance() {
  const [count, setCount] = useState(0);
  const [show, setShow] = useState(true);

  useEffect(() => {
    console.log("修改DOM");
  }, [count])

  return (
    <div>
      <h2>當(dāng)前計(jì)數(shù): {count}</h2>
      <button onClick={e => setCount(count + 1)}>+1</button>
      <button onClick={e => setShow(!show)}>切換</button>
    </div>
  )
}

但是,如果一個(gè)函數(shù)我們不希望依賴任何的內(nèi)容時(shí),也可以傳入一個(gè)空的數(shù)組 []

三、Context Hook的使用(useContext)

Context Hook可以讓我們通過Hook來直接獲取某個(gè)Context的值:

const value = useContext(MyContext);

在App.js中使用Context:

import React, { createContext } from 'react';

import ContextHook from './04_useContext使用/01_ContextHook';

export const UserContext = createContext();
export const ThemeContext = createContext();

export default function App() {
  return (
    <div>
      <UserContext.Provider value={{name: "why", age: 18}}>
        <ThemeContext.Provider value={{color: "red", fontSize: "20px"}}>
          <ContextHook/>
        </ThemeContext.Provider>
      </UserContext.Provider>
    </div>
  )
}

在對(duì)應(yīng)的函數(shù)式組件中使用Context Hook:

import React, { useContext } from 'react'
import { UserContext, ThemeContext } from '../App'

export default function ContextHook() {
  const user = useContext(UserContext);
  const theme = useContext(ThemeContext);
  console.log(user);
  console.log(theme);

  return (
    <div>
      ContextHook
    </div>
  )
}

四、關(guān)于useReducer Hook的使用 (useReducer)

useReducer僅僅是useState的一種替代方案:

  • 在某些場(chǎng)景下,如果state的處理邏輯比較復(fù)雜,我們可以通過useReducer來對(duì)其進(jìn)行拆分;
  • 或者這次修改的state需要依賴之前的state時(shí),也可以使用;

單獨(dú)創(chuàng)建一個(gè)reducer/counter.js文件:

export function counterReducer(state, action) {
  switch(action.type) {
    case "increment":
      return {...state, counter: state.counter + 1}
    case "decrement":
      return {...state, counter: state.counter - 1}
    default:
      return state;
  }
}

home.js文件:

import React, { useReducer } from 'react'
import { counterReducer } from '../reducer/counter'

export default function Home() {
  const [state, dispatch] = useReducer(counterReducer, {counter: 100});

  return (
    <div>
      <h2>當(dāng)前計(jì)數(shù): {state.counter}</h2>
      <button onClick={e => dispatch({type: "increment"})}>+1</button>
      <button onClick={e => dispatch({type: "decrement"})}>-1</button>
    </div>
  )
}

profile.js文件(創(chuàng)建另外一個(gè)profile.js也使用這個(gè)reducer函數(shù)):

import React, { useReducer } from 'react'
import { counterReducer } from '../reducer/counter'

export default function Profile() {
  const [state, dispatch] = useReducer(counterReducer, {counter: 0});

  return (
    <div>
      <h2>當(dāng)前計(jì)數(shù): {state.counter}</h2>
      <button onClick={e => dispatch({type: "increment"})}>+1</button>
      <button onClick={e => dispatch({type: "decrement"})}>-1</button>
    </div>
  )
}

通過執(zhí)行可以發(fā)現(xiàn),home.js文件和profile.js文件在使用的時(shí)候,counter并不會(huì)共享,也就是說home文件中修改counter的值不會(huì)影響profile中counter的值,同理修改profile文件中counter也是。
所以,useReducer只是useState的一種替代品,將復(fù)雜的useState拆分到不同的文件中,并不能替代Redux。

最后編輯于
?著作權(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ù)。

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