React在項目中使用Hooks

Hooks是React 16.8中的新增功能。它們允許您在不編寫類class的情況下使用狀態(tài)state和其他React功能。
要使用Hooks請先升級你的React包,包括ReactDom。

為什么使用Hooks

我們總是會遇到某些困惑,比如:

  • 當我們定義的一個組件只用到一兩個state狀態(tài)變量
  • 一個組件只用到用到了生命周期某一個方法例如componentDidMountcomponentWillUpdate、componentWillMount

為了解決上面的問題,我們不得不定義一個class component,來達到我們的目的,看起來代碼有很多的冗余。而hooks就是幫我們解決這些問題,讓我們可以拋棄class component擁抱function component,使代碼看起來清晰,整潔。

如何使用useState

引用官方的一個例子:

import React, { useState } from 'react';

function Example() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

看一下上面做了什么操作:

  1. 定義了一個名稱為Examplefunction component
  2. 使用useState在這個方法內(nèi)部定義了一個變量count
  3. 并暴露了一個修改count的方法setCount
  4. 每次點擊按鈕對count遞增

如果我們用class component是如何實現(xiàn)上面的步驟的呢?等效于:

class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>
    );
  }
}

一對比我們會發(fā)現(xiàn)使用Hooks能讓代碼看起來更加有條理,簡潔,也能使狀態(tài)和UI層分離
當然Hooks能讓我們可以定義多個狀態(tài),每個狀態(tài)都是獨立的

function ExampleWithManyStates() {
  // Declare multiple state variables!
  const [age, setAge] = useState(42);
  const [fruit, setFruit] = useState('banana');
  const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);

同時我們會想到如果有很多個狀態(tài),我們要寫多個useState,Hooks支持狀態(tài)值是對象,我們也可以這樣寫:

  const [data, setData] = useState({age: 42, fruit: 'banana', todos: [{ text: 'Learn Hooks' }]});

需要注意的是,上面的方括號[data, setData]并不是Hooks的語法,而是JavaScript數(shù)組結構

如何使用useEffect

我們常常需要在組件加載的時候就需要運行某些函數(shù),異步請求數(shù)據(jù),我們可能會這樣寫:

import { Component } from 'react';
import axios from 'axios'

class Exampel extends Component {
  constructor(props) {
    super(props);
     this.state = {
       data: null
     };
  }
 
 getItem = () => {
    axios
      .post('請求url')
      .then(res => {
         this.setState{
           data: res.data
         }
      })
      .catch(err => console.error(err))
  }

  componentDidMount () {
    this.getItem()
  }

  //...
}

使用HooksuseEffect我們可以這樣寫:

import { useState, useEffect } from 'react'
import axios from 'axios'

function Example(){
  const [data, setData] = useState([]);

  function getItem () {
    axios
      .post('請求url')
      .then(res => {
       setData(res.data)
      })
      .catch(err => console.error(err))
  }

  useEffect(() => {
    getItem()
  }, [])

  //...
}

當然我開始也是這樣寫的,毫無疑問這樣寫目前看起來沒有什么問題,能達到預期的效果。
但是有時候我會發(fā)現(xiàn)使用useEffect的時候,里面的函數(shù)被無限循環(huán)調(diào)用了,這當然和我想象的初始化的時候只執(zhí)行一次出入很大,這是為什么呢?
我們來看個例子:
在發(fā)送請求的時候,往往我們會添加一些參數(shù):

import { useState, useEffect } from 'react'
import axios from 'axios'

function Example(){
  const [data, setData] = useState([]);
  const [params, setParams] = useState({});

  function getItem () {
    axios
      .post('請求url', params) //注意我在這里使用了另一個狀態(tài)params
      .then(res => {
       setData(res.data)
      }) 
      .catch(err => console.error(err))
  }

  useEffect(() => {
    getItem()
  }, [getItem]) //在參數(shù)改變的時候調(diào)用

  //...
}

上面的例子,我在useEffect 里的依賴函數(shù)getItem又對返回函數(shù)data賦值,使得每次data改變的時候useEffect就會被觸發(fā),導致了無限循環(huán)。
解決方法就是把useEffect的第二個參數(shù)改成[]也就是useEffect(() => {....}, []),這意味著效果函數(shù)應該被調(diào)用一次:僅在第一次裝載/渲染之后。但是這并不符合Hooks規(guī)范?;蛘呤悄阋男Ч褪莗arams改變后再次調(diào)用請求,用useCallback看看能否解決問題。

import { useState, useEffect, useCallback } from 'react'
import axios from 'axios'

function Example(){
  const [data, setData] = useState([]);
  const [params, setParams] = useState({});

  const getItem = useCallback(() => { //使用useCallback解決依賴函數(shù)的不可控變量
    axios
      .post('請求url', params) //注意我在這里使用了另一個狀態(tài)params
      .then(res => {
       setData(res.data)
      }) 
      .catch(err => console.error(err))
  }, [params, setData])//在useCallback里檢查變量的改變

  useEffect(() => {
    getItem()
  }, [getItem]) //符合useEffect規(guī)范

  //...
}

我們推薦使用上面這種方法解決避免useEffect無限循環(huán)
無限循環(huán)調(diào)用產(chǎn)生的原因主要有以下幾種,你可以一個個排除看看:

  1. 是不是在依賴函數(shù)里重新設置了狀態(tài)
  2. 是什么操作引起了父組件重新render,導致本身組件也被重新加載,引起無限循環(huán)
  3. useEffect是不是被放在了判斷if語句或者循環(huán)for語句里面了
    當然我們還這樣使用:
useEffect(() => {
    function getItem () {
      axios
        .post('https://www.easy-mock.com/mock/5b4eb12d56c59c6f56266215/api/order_list', params) // 注意我在這里使用了另一個狀態(tài)params
        .then(res => {
          setData(res.data)
        })
        .catch(err => console.error(err))
    }
    getItem()
  }, [params, setData])

useEffect所有依賴的函數(shù)放在useEffect里面,讓useEffect變得自給自足,這樣我們減少了很多不可控制的因素,方法里面所有的依賴項都是可見的可控的。
還有一些Hooks提供的方法useRef、useCallback等好用的方法可以查看官網(wǎng)API https://reactjs.org/docs/hooks-reference.html

總結:使用Hooks的好處:

  1. 可以讓我們放棄class component ,擁抱function component
  2. 可以在function component使用狀態(tài)且是獨立的狀態(tài),可以獨立維護,這和狀態(tài)組件有著很大的區(qū)別
  3. 可以讓我們一個個組件去做優(yōu)化,不需要全部重構
  4. 使狀態(tài)與UI分離
  5. 讓我們的代碼看起來更加有條理、清晰、簡潔

tips: 簡書上交流可能會看不到消息,如有問題,歡迎進群交流50063010
參考鏈接1:https://reactjs.org/docs/hooks-intro.html
參考鏈接2:https://overreacted.io/a-complete-guide-to-useeffect/

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

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