一次性瞭解React中Hooks

我的掘金:https://juejin.im/post/5c988b...

1. 前言

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

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

在使用Hooks之前我們必須知道的幾件事:

  • Hooks的使用完全根據我們的需要進行選擇用還是不用。
  • Hooks是完全向下兼容。
  • Hooks現在完全可用。
  • Hooks的出現並沒有改變我們之前對react的理解。
  • Hooks的出現並沒有移除classes的計劃。

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

  • 很難重用組件之間有狀態的邏輯
  • 複雜的組件變得難以理解

2. State Hook(useState)

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

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。我們可以稱爲這些爲副作用。因爲這些操作可能會影響到其他組件或者不能在渲染組件中完成。

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函數。

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'
}

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

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。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章