React中Hooks

1. 前言

Hooks是React16.8版本中的新特性,它能夠在不使用class聲明的組件中使用state和React特性。react

Tip: React v16.8.0已經支持Hooks。當咱們進行更新時,別忘了更新其餘相關依賴包,包括React DOM等。React Native將會在下一個穩定版本支持Hooks。數組

在使用Hooks以前咱們必須知道的幾件事:bash

  • Hooks的使用徹底根據咱們的須要進行選擇用仍是不用。
  • Hooks是徹底向下兼容。
  • Hooks如今徹底可用,已經發布與v16.8.0。
  • Hooks的出現並無改變咱們以前對react的理解。
  • Hooks的出現並無移除classes的計劃。

那麼Hooks出現的動機是什麼:函數

  • React須要爲共享狀態提供更好的原生途徑。
  • 很難重用組件之間有狀態的邏輯。
  • render props和高階組件會改變組件結構。
  • 複雜的組件變得難以理解。

2. State Hook(useState)

先來介紹第一個useState。能夠在函數組件(function component)使用它。它在的做用是添加本地狀態到當前組件。React會一直維持在這個state。useState將會有兩個返回值:當前的state和一個更新state的方法。 調用useState時傳入的參數表示着initial State。咱們能夠屢次調用useState在同一個組件中,表示建立多個狀態。ui

import React, { useState } from 'react'

    const HookDemo = ({}) => {
    const [count, setCount] = useState(0)
    const [number, setNumber] = useState(2)
    const [todos, setTodos] = useState([{text: 'huzhiwei'}])

    const setHandle = () => {
      todos[0].text = 'jp'
      setTodos(Object.assign({}, todos))
    }
    return (
      count: {count}
      number: {number}
      todos: {todos[0].text}
      <button onClick={()=>setCount(count+1)}>count handler</button>
      <button onClick={()=>setNumber(number+1)}>number handler</button>
      <button onClick={()=>setHandle()}>todos handler</button>
    )
}
複製代碼

3. Effect Hook (useEffect)

咱們可能執行過請求獲取數據,監聽,或者手動改變DOM。咱們能夠稱爲這些爲反作用。由於這些操做可能會影響到其餘組件或者不能在渲染組件中完成。spa

Effect Hook給函數組件增長了處理反作用的能力。能夠理解它的能力和componentDidMount、componentDidUpdate、componentWillUnmount相似。useEffect將這些統一爲一個單獨的API。 以下是React文檔中的例子:插件

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

function Example() {
    const [count, setCount] = useState(0)
    
    useEffect(() => {
        document.title = 'good body'
    })
    
    return (
        <div>
            <span>{ count }</span>
            <button onClick={()=>setCount(count + 1)}>click me</button>
        </div>
    )
}   
複製代碼

當咱們調用useEffect時,就是告訴React在刷新對DOM的更改後執行effect函數。React會在每次渲染後執行effect函數。eslint

effect還能夠選擇性地指定如何經過返回函數在它們以後「清理」。例如,該組件使用一個效果來訂閱朋友的在線狀態,並經過取消訂閱來清理:code

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'
}
複製代碼

在這個例子中,當組件unmount的時候React將會經過ChatAPI取消訂閱。在後續的render又將會從新執行這些effect。component

Tip: 咱們在組件中也能夠像useState同樣屢次調用。

effect在第一次組件掛載和後面組件更新時都會執行,這樣就會致使一些非必要的effect重複執行。若是咱們想經過對比先後數據是否發生改變來判斷是否觸發effect,咱們能夠經過傳入數組做爲第二個參數:

useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]); // 僅在 count 更改時更新
複製代碼

若是你想要執行只運行一次的 effect(僅在組件掛載和卸載時執行),你能夠傳遞一個空數組([])做爲第二個參數。這就告訴 React 你的 effect 不依賴於 props 或 state 中的任何值,因此它永遠都不須要重複執行。這並不算是一種特殊狀況 —— 依然遵循輸入數組的工做方式。

4. 建立自定義Hooks

有些場景下,咱們想複用一些關於狀態的邏輯。一般會有兩種經常使用的解決方案:高階組件render Props。自定義Hooks也能夠作這些,並且不須要增長更多的組件。

這裏有個例子使用useStateuseEffect去監聽好友是否在線狀態。咱們想重用這個監聽邏輯在不一樣的組件中該怎麼作呢?

首先抽象出這個邏輯到一個自定義組件中,叫作useFriendStatus:

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

function useFriendStatus(frientID) {
    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>
  );
}
複製代碼

這些組件的狀態是徹底獨立的。鉤子是重用有狀態邏輯的一種方法,而不是狀態自己。事實上,每一個對鉤子的調用都有一個徹底獨立的狀態——因此您甚至能夠在一個組件中兩次使用相同的自定義鉤子。

5. Hooks規則

  • Hooks只在頂層調用,不要在循環,條件判斷或者嵌套函數中調用鉤子。
  • 只在React的函數組件(function Component)中調用Hooks。
  • 對於自定義Hooks,咱們使用use開頭命名。
  • eslint-plugin-react-hooks該插件能夠規範hooks寫法。
  • React 靠的是 Hook 調用的順序來對應state和useState。
相關文章
相關標籤/搜索