Hooks是React16.8版本中的新特性,它能夠在不使用class聲明的組件中使用state和React特性。react
Tip: React v16.8.0已經支持Hooks。當咱們進行更新時,別忘了更新其餘相關依賴包,包括React DOM等。React Native將會在下一個穩定版本支持Hooks。數組
在使用Hooks以前咱們必須知道的幾件事:bash
那麼Hooks出現的動機是什麼:函數
先來介紹第一個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>
)
}
複製代碼
咱們可能執行過請求獲取數據,監聽,或者手動改變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 中的任何值,因此它永遠都不須要重複執行。這並不算是一種特殊狀況 —— 依然遵循輸入數組的工做方式。
有些場景下,咱們想複用一些關於狀態的邏輯。一般會有兩種經常使用的解決方案:高階組件和render Props。自定義Hooks也能夠作這些,並且不須要增長更多的組件。
這裏有個例子使用useState和useEffect去監聽好友是否在線狀態。咱們想重用這個監聽邏輯在不一樣的組件中該怎麼作呢?
首先抽象出這個邏輯到一個自定義組件中,叫作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>
);
}
複製代碼
這些組件的狀態是徹底獨立的。鉤子是重用有狀態邏輯的一種方法,而不是狀態自己。事實上,每一個對鉤子的調用都有一個徹底獨立的狀態——因此您甚至能夠在一個組件中兩次使用相同的自定義鉤子。