React Hooks(30分鐘全掌握)

介紹React Hooks

Hooks是React 16.8新增長的特性,Hooks可讓你不寫class組件就能使用state和其餘React特性。react

例子

import React, {useState} from 'react';
    
    function Example() {
        const [count, setState] = useState(0);
        
        return (
            <div>
                <p>你點擊了{count}次</p>
                <button onClick={()=>setCount(count + 1)}>
                </button>
            </div>
        )
    }
複製代碼

useState是要學的第一個'Hooks',上面就是簡單的使用案例。數組

接下來是講爲何在React中加入Hooks而且怎麼幫助你寫出更好的應用。若是你想學Hooks請點擊下一個章節Hooks概覽bash

Hooks概覽

Hooks是向後兼容。上面的例子👆中,按鈕每點擊一次數字加1。其中useState是一個Hook。
在函數組件中調用useState是爲了在其中加入state(即函數內部狀態)。在從新渲染的時候React將會保留這個state。 useState返回一對值:當前的狀態 和 更新狀態的函數(即dispatch函數)。你能夠在事件處理函數中或其餘地方調用dispatch函數更新狀態.
useState相似於在類組件中this.setState,不一樣是Hook沒有將新舊狀態合併在一塊兒。下一章將會對useStatethis.setState做對比。frontend

useState惟一的參數就是初始化值。在上面的例子中,初始化值是0.注意:不一樣於this.setState,這裏的state不用必須是一個Object。初始化值僅在第一次渲染的時候用到。dom

聲明多個state變量

const [name, setName] = useState('paprika');
    const [position, setPosition] = useState('frontend developer');
    const [plans, setPlans] = useState([{title: 'dance'}]);
複製代碼

數組解構讓咱們能夠給經過調用useState聲明的state變量賦任意的名稱。這些名字不是useState的API。而是React假設若是你屢次調用useState,在每次渲染的時候你都將會以相同的順序使用這些狀態。以後會解釋如何這樣作以及何時這種假設有用。ide

什麼是Hook?

Hooks是讓你勾住React state和在函數組件中使用生命週期特性的函數。
Hooks在class組件中不會起做用-(讓你不用class就能夠用react的state和其餘特性)
注意:官方不推薦所有重寫已經存在的組件,可是能夠在新的組件中嘗試使用Hooks。(可是國外有人說:2018年class是代名詞,2019年class已成爲過去,他們的項目已經用Hooks擴展,再也不用class了) 函數

React提供了少許像useState這樣的內置Hook。你也能夠寫本身的Hooks以便在不一樣組件之間實現狀態重用。咱們首先看內置Hooks。動畫

Effect Hooks

以前你可能已經進行了數據獲取,訂閱和手動修改dom。咱們稱這些操做是:反作用(side effect)。由於這些操做影響其餘組件而且在渲染的時候沒法完成。ui

useState是一個Effect Hook並在功能組件中添加了執行反作用的功能。它和在class組件中componentDidMount componentDidUpdate componentWillUnmount的目的同樣。可是合併成了一個單獨的API,下下章將會作個對比。this

例如:React更新dom以後,組件設置標題

import React, {useState, useEffect} from 'react';
    
    function Example() {
        const [count, setCount] = useState(0);
        
        useEffect(() => {
            document.title = `你點擊了${count}次`;
        })
        
        return (
            <div>
              <p>You clicked {count} times</p>
              <button onClick={() => setCount(count + 1)}>
                Click me
              </button>
            </div>
        );
    }
複製代碼

當你調用 useEffect,React就會在刷新DOM更改以後調用你的effect函數。Effects定義在組件內部,因此有權訪問props 和 state。默認React在每次渲染以後執行effect函數,包括第一次渲染。(後文比較useEffect和class的生命週期)

useEffect能夠選擇返回一個函數來清理已經不須要的內容。下面例子,組件用了一個effect去訂閱在線朋友數,經過取消訂閱來移除它。

import React, {useState, useEffect} from 'react';
    
    function FriendStatus(props) {
        const [isOnline, setIsOnline] = useState(null);
        
        function handleStatusChange(status) {
            setIsOnline(status.isOnline);
        }
        
        useEffect(()=>{
            ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);

            return () => {
              ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
            };
        });
        
        if (isOnline === null) {
            return 'Loading...';
        }
        return isOnline ? 'Online' : 'Offline';
    }
複製代碼

這個例子,當組件卸載 以及 後續渲染從新運行effect以前,React將會取消訂閱 ChatAPI。(跳太重新訂閱的方法是提供id)

就像useState,你能夠在一個組件用多個effect:

function FriendStatusWithCounter(props) {
  const [count, setCount] = useState(0);
  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

  const [isOnline, setIsOnline] = useState(null);
  useEffect(() => {
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

  function handleStatusChange(status) {
    setIsOnline(status.isOnline);
  }
  // ...
複製代碼

Hooks讓你經過相關部分組織反作用(例如:添加和刪除訂閱),而不是經過生命週期強行拆分。

Hooks規則

Hooks是JavaScript函數,可是加了兩個規則:

  1. 僅在頂層調用Hooks。不要在循環內部、判斷和嵌套函數中調用Hooks。
  2. 僅在React函數組件調用Hooks。在普通js函數中不要調用Hooks。(你本身的Hooks能夠調用)

官方提供linter插件去自動執行這些規則。理解規則對於運行好Hooks相當重要。

構建你本身的Hooks

有時你可能想在不一樣組件之間重用狀態邏輯。傳統有兩種解決方法: 高階組件 和 組件注入(render props)。自定義組件能夠作到這些而且不用添加額外的東西。

上面介紹了FriendStatus組件,其調用useStateuseEffectHooks去訂閱朋友在線狀態。假設咱們想要在類外一個組件重用訂閱邏輯。

首先,在提取邏輯到本身的Hooks,命名爲useFriendStatus:

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

function useFriendStatus(friendID) {
  const [isOnline, setIsOnline] = useState(null);

  function handleStatusChange(status) {
    setIsOnline(status.isOnline);
  }

  useEffect(() => {
    ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
    };
  });

  return isOnline;
}
複製代碼

friendID是參數,返回朋友是否在線。

接下來在不一樣組件使用:

function FriendStatus(props) {
  const isOnline = useFriendStatus(props.friend.id);

  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}
複製代碼
function FriendListItem(props) {
  const isOnline = useFriendStatus(props.friend.id);

  return (
    <li style={{ color: isOnline ? 'green' : 'black' }}>
      {props.friend.name}
    </li>
  );
}
複製代碼

不一樣組件的state是徹底獨立。Hooks是重用邏輯的一種方法,而不是狀態自己。事實上,每次調用Hooks都是徹底獨立的狀態,所以,你能夠在一個組件用兩次Hooks。

自定義Hooks更可能是一個約定而不是特性。若是一個函數以use開始命名 而且 調用了其餘Hooks,咱們就叫它自定義Hook。這個useSomething命名約定是linter插件用hooks查找bug的關鍵。

你能夠用自定義Hooks覆蓋普遍的用例,像表單處理、動畫、聲明訂閱、定時器和其餘更多的咱們沒想到的。期待更多的場景由社區提供。

其餘Hooks

你可能發現其餘不經常使用的內置Hooks頗有用,例如useContext讓你引入上下文而不嵌套。

function Example() {
  const locale = useContext(LocaleContext);
  const theme = useContext(ThemeContext);
  // ...
}
複製代碼

useReducer容許您使用reducer管理複雜組件的本地狀態:

function Todos() {
  const [todos, dispatch] = useReducer(todosReducer);
  // ...
複製代碼
相關文章
相關標籤/搜索