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是向後兼容。上面的例子👆中,按鈕每點擊一次數字加1。其中useState
是一個Hook。
在函數組件中調用useState
是爲了在其中加入state(即函數內部狀態)。在從新渲染的時候React將會保留這個state。 useState
返回一對值:當前的狀態 和 更新狀態的函數(即dispatch函數)。你能夠在事件處理函數中或其餘地方調用dispatch函數更新狀態.
useState
相似於在類組件中this.setState
,不一樣是Hook沒有將新舊狀態合併在一塊兒。下一章將會對useState
和this.setState
做對比。frontend
useState
惟一的參數就是初始化值。在上面的例子中,初始化值是0.注意:不一樣於this.setState
,這裏的state不用必須是一個Object。初始化值僅在第一次渲染的時候用到。dom
const [name, setName] = useState('paprika');
const [position, setPosition] = useState('frontend developer');
const [plans, setPlans] = useState([{title: 'dance'}]);
複製代碼
數組解構讓咱們能夠給經過調用useState
聲明的state變量賦任意的名稱。這些名字不是useState
的API。而是React假設若是你屢次調用useState
,在每次渲染的時候你都將會以相同的順序使用這些狀態。以後會解釋如何這樣作以及何時這種假設有用。ide
Hooks是讓你勾住React state和在函數組件中使用生命週期特性的函數。
Hooks在class組件中不會起做用-(讓你不用class就能夠用react的state和其餘特性)
注意:官方不推薦所有重寫已經存在的組件,可是能夠在新的組件中嘗試使用Hooks。(可是國外有人說:2018年class是代名詞,2019年class已成爲過去,他們的項目已經用Hooks擴展,再也不用class了) 函數
React提供了少許像useState
這樣的內置Hook。你也能夠寫本身的Hooks以便在不一樣組件之間實現狀態重用。咱們首先看內置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是JavaScript函數,可是加了兩個規則:
官方提供linter插件去自動執行這些規則。理解規則對於運行好Hooks相當重要。
有時你可能想在不一樣組件之間重用狀態邏輯。傳統有兩種解決方法: 高階組件 和 組件注入(render props)。自定義組件能夠作到這些而且不用添加額外的東西。
上面介紹了FriendStatus
組件,其調用useState
和useEffect
Hooks去訂閱朋友在線狀態。假設咱們想要在類外一個組件重用訂閱邏輯。
首先,在提取邏輯到本身的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頗有用,例如useContext
讓你引入上下文而不嵌套。
function Example() {
const locale = useContext(LocaleContext);
const theme = useContext(ThemeContext);
// ...
}
複製代碼
useReducer
容許您使用reducer管理複雜組件的本地狀態:
function Todos() {
const [todos, dispatch] = useReducer(todosReducer);
// ...
複製代碼