react的新特性之react-hooks

最近組內大佬給小編安排了一個任務,整理一份關於react-hooks的簡單的使用教程。javascript

看到消息的時候有點欣喜,由於小編以前就想整理,奈何抵不過惰性,正好趁着此次機會,把hooks相關的知識點學習並鞏固一下(雖然沒有用過,可是期待在之後的項目中嘗試)。 java

這篇文章會圍繞hook的特性以及基本使用方式,State hookEffect hook,useContext以及自定義hook展開,有興趣的童鞋能夠停下腳步,稍微瞭解一下。react


Hook是什麼?

首先,咱們須要知道的是,hookreact 16.8的新增特性,他的最特別的一點就是命名的時候必定要以use開頭。不要問我爲何,多是爲了便於識別是否爲hooks的一種手段吧。數組

在這裏,不得不說一下linter這個插件,這是專門用來檢查hook格式的一個插件,pick它吧。bash

其次,hook是一些可讓你在函數組件內「鉤入」 React state 以及生命週期等特性的函數。(例如,useState 是容許你在 React 函數組件中添加 stateHookhook不能在class組件中使用,這就使得咱們在不寫class組件時,也能使用hook。網絡

最後,hook 100%向下兼容。hook也能夠將組件中相互關聯的部分拆分紅更小的函數(好比設置訂閱,請求數據等)。app

⚠️hook就是javascript函數,可是使用其有兩個額外的原則:ide

1.只能在函數最外層調用hook函數

2.只能在react的函數組件中調用hook學習

3.不要在循環,條件或嵌套以及普通的javascript中調用hook


基本用法

首先,看官網給的一個比較簡單的計數器示例:

import React, { useState } from 'react';

function Example() {
  // 聲明一個叫 「count」 的 state 變量。
  const [count, setCount] = useState(0);

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

能夠看到,它引用了useState,而後聲明瞭一個初始值爲0的count的變量,經過setCount這個方法去直接改變count的值。

這裏的onClick={() => setCount(count + 1)}在沒有hook以前,能夠理解爲onClick={this.setcount},而後在聲明的setCount方法內進行this.setState({count: count + 1})操做。

以上能夠看出,使用hook方便不少,在精簡了代碼的基礎上,還能夠去掉傳統this指向等繁瑣的問題。

咱們再來看另外一個配合ant design使用的例子:

function Example() {
  const [open, setOpen] = useState(false);
  return (
    <>
      <Button type="primary" onClick={() => setOpen(true)}>
        Open Modal
      </Button>
      <Modal
        visible={open}
        onOk={() => setOpen(false)}
        onCancel={() => setOpen(false)}
      />
    </>
  );
}
複製代碼

拓展一下,咱們能夠經過給按鈕設置初始值來控制彈窗的彈出與關閉等等。


State hook

使用useState時,咱們須要知道的總結一下大概有如下幾點:

1.state是隻讀的;

2.useState函數的第一個參數,是state變量的初始值;

3.每次進行渲染時,多個State Hook的順序、數量都必須同樣;

4.state變量發生變化時,會觸發新的渲染;state變量沒變化,不觸發新的渲染;

使用state hook的主要做用就是獲取須要的 state和 更新state的方法,以官網例子爲例:

const [state, setState] = useState(initialState);
複製代碼

參數: initialState能夠做爲state的一個初始值,同時,他也能夠是一個函數,返回值做爲state的初始值,該參數只會在初始渲染時起做用。

返回值: 會返回一個數組,一個是state的值,另外一個是更新state值的一個方法。(這裏的setState不會合並state的值)。

若是要定義多個變量,能夠屢次使用useState

小編以爲,官網關於state hook部分有一個小技巧值得一提,以下:

var fruitStateVariable = useState('banana'); // 返回一個有兩個元素的數組
  var fruit = fruitStateVariable[0]; // 數組裏的第一個值
  var setFruit = fruitStateVariable[1]; // 數組裏的第二個值
複製代碼

使用數組解構來將定義的變量經過[0],[1],解構到原來setState返回的兩個值的數組當中。


Effect hook

數據獲取,設置訂閱以及手動更改 React 組件中的 DOM都屬於反作用。Effect Hook可讓咱們在函數組件中經過使用useEffect提高操做反作用的能力,它在渲染以後執行,咱們能夠把它看作 componentDidMountcomponentDidUpdatecomponentWillUnmount這三個函數的組合。

簡單的理解就是:useEffect跟以上三個生命週期用途相同,只不過被合併成了一個API

在使用useEffect的時候,須要考慮兩點:須要清除和不須要清除。那麼什麼狀況下須要清除,什麼狀況下又不須要清除呢?小編帶你來了解

須要清除反作用的狀況

當訂閱外部數據源的時候,須要清除數據。數據須要清除,能夠返回一個函數。

以官網的例子爲例:

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

function FriendStatus(props) {
  const [isOnline, setIsOnline] = useState(null);

  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }

    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    // Specify how to clean up after this effect:
    return function cleanup() {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}
複製代碼

爲了避免會引發內存泄漏,訂閱外部數據源時須要清除數據。effect返回一個函數是由於這是effect 可選的清除機制,同時,React會在組件卸載的時候執行清除操做。

固然,在hook還沒出來以前,使用class建立組件訂閱外部數據源時,清除方式以下(此處依舊引用官網代碼):

class FriendStatus extends React.Component {
  constructor(props) {
    super(props);
    this.state = { isOnline: null };
    this.handleStatusChange = this.handleStatusChange.bind(this);
  }

  componentDidMount() {
    ChatAPI.subscribeToFriendStatus(
      this.props.friend.id,
      this.handleStatusChange
    );
  }
  
  componentDidUpdate(prevProps) {
    // 取消訂閱以前的 friend.id
    ChatAPI.unsubscribeFromFriendStatus(
      prevProps.friend.id,
      this.handleStatusChange
    );
    // 訂閱新的 friend.id
    ChatAPI.subscribeToFriendStatus(
      this.props.friend.id,
      this.handleStatusChange
    );
  }

  componentWillUnmount() {
    ChatAPI.unsubscribeFromFriendStatus(
      this.props.friend.id,
      this.handleStatusChange
    );
  }

  handleStatusChange(status) {
    this.setState({
      isOnline: status.isOnline
    });
  }

  render() {
    if (this.state.isOnline === null) {
      return 'Loading...';
    }
    return this.state.isOnline ? 'Online' : 'Offline';
  }
}
複製代碼

當使用class建立一個組件,而且使用了componentDidMount訂閱,在componentDidUpdate中更新訂閱,在componentWillUnmount清除。

能夠看到,較使用effect來講,class清除反作用時代碼較爲冗餘。

無需清除反作用的狀況

effect內只有單行代碼,或者咱們只想在React更新DOM 以後運行一些額外的代碼。好比發送網絡請求,手動變動 DOM,記錄日誌,這些無需清除的操做。 如官網代碼所示:

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

function Example() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

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

這種狀況下無需清除反作用。

還有一點咱們應該要注意的是,咱們須要跳過一些沒必要要反作用函數。那麼,如何才能跳過呢?這裏就要講到useEffect的第二個參數。

咱們須要給useEffect的傳入第二個參數,當第二個參數改變時,執行反作用;當參數不改變時,可直接跳過反作用不執行。例子以下:

useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]); // 當count的值更新時,纔會從新執行`document.title`
複製代碼

useContext的使用

咱們先來看個例子:

import React from 'react';

const appContext = React.createContext();  //建立一個context
functuion App() {
    return (
       <appContext.Provider value={888}> //這使用了Provider主要是爲全部後代提供value值
           <div>
               <Show />
           </div>
       
       </appContext.Provider>
    )
}

function Show() {
    return (
        <appContext.Consumer> //使用Consumer獲取到value的值
            {value => <div>{value}</div>}
        </appContext.Consumer>
    )
}
複製代碼

首先咱們能夠看到,使用contextAPI的方式下,能夠經過建立一個context上下文,返回一個帶有{Provider, Consumer}的值的對象,而後經過使用Provider主要是爲全部後代提供value值,這避免了以往手動一個個向子孫組件傳遞prop

而後,可使用Consumer能夠從上下文獲取value的值。須要注意的一點是,這個Consumer 子組件,在這裏只能是惟一的一個函數。

再來看一下使用useContext的狀況

import React, { useContext } from 'react';

const appContext = React.createContext();  //建立一個context
functuion App() {
    return (
       <appContext.Provider value={888}> //這使用了Provider主要是爲全部後代提供value值
           <div>
               <Show />
           </div>
       
       </appContext.Provider>
    )
}

function Show() {
    const apps = useContext(appContext);
    return (
        {value => <div>{apps}</div>}
    )
}
複製代碼

這裏調用useContext,傳入從React.createContext()獲取到的上下文對象。須要注意的一點是,useContext 的參數必須是 context 對象自己,即useContext(appContext),而不是useContext(appContext.Provider)useContext(appContext.consumer)


自定義hook

前面已經講到,hook通常以use開頭,自定義hook也同樣。自定義 hook 是一個函數,其名稱以 use開頭(必須),函數內部能夠調用其餘的hook

當項目中,咱們想要共享組件之間的狀態邏輯時,最多見的方法是使用高階組件或者 render props。可是,使用自定義的hook能夠是你在不增長組件的前提之下,把公用邏輯提取出來進行復用。

(詳情可查看官網:react.docschina.org/docs/hooks-…

以上就是小編此次對於react-hooks知識點的一個大概的梳理,如有錯誤,歡迎指出,一塊兒學習,一塊兒進步。(若覺尚可,可暗戳戳筆芯)

相關文章
相關標籤/搜索