前沿
想寫下react hooks ,一些基本資料,當然也可以看官網,我只是整理下
react hooks 的官方基本介紹可以看 React 的文檔:https://reactjs.org/docs/hooks-intro.html
一、State Hook
以一個簡單的計數器舉例,使用 useState
這個 Hook:
import { useState } from 'react'; function Example() { // Declare a new state variable, which we'll call "count" const [count, setCount] = useState(0); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }
上面的 useState
實際上就是一個 Hook,我們在函數組件中調用它來向它添加一些本地的 state,而 React 在 re-render 之前會保留這個 state。useState
返回兩個內容:
- 當前的 state 值
- 一個允許更新 state 值的 function
可以從事件處理程序或者其他位置調用返回的 function,和類中的 this.setState 比較累色,只不過不會將新的 state 和舊的 state 合並在一起。(React 給過一個使用 useState 和 this.state 的比較的示例https://reactjs.org/docs/hooks-state.html)
useState
的唯一參數是初始狀態,在上面的例子中,初始 state 是 0,因為計數器從 0 開始。請注意,和 this.state 不同的是,這里的 state 不一定是對象,可以是隨便需要的形式。而初始狀態參數僅僅在第一次渲染的時候使用。
1、聲明多個 state 變量
可以在單個組件中多次使用 state Hook:
function ExampleWithManyStates() { // Declare multiple state variables! const [age, setAge] = useState(42); const [fruit, setFruit] = useState('banana'); const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]); // ... }
數組結構語法允許給 useState 的聲明的 state 變量賦予不同的名稱,這些名稱並不是 useState API 的一部分。相反,React 假定如果多次調用 useState,則在每次渲染期間,以相同的順序執行。
2、什么是 Hook
Hook 是允許從功能組件 掛鈎
React 的 state 和生命周期方法等功能。Hook 在類的內部不起作用——允許在沒有類的情況下使用 React。(React 不建議全部重寫組件,只是建議如果感興趣 Hook,可以在新的組件中使用)
React 提供了一些像 useState
這樣的內置 Hook,還可以創建自己的 Hook 以便於重用不同組件之間的狀態行為。
二、Effect Hook
我們已經可以在 React 組件中進行數據請求、subscriptions 或者是手動更改 DOM。
這些操作都是稱為 side effects
,也就是副作用。因為它們會影響其他組件,並且在渲染過程中沒有辦法完成。
useEffect
增加了從功能組件執行副作用的功能。它與 React 類的 componentDidMount
、componentDidUpdate
和 componentWillUnmount
具有相同的效果,但是統一成了一個 API。可以在 Using the Effect Hool 文檔中查找關於更多 useEffect
的內容。
例如,下面的組件在 React 更新 DOM 后設置文檔標題:
import { useState, useEffect } from 'react'; function Example() { const [count, setCount] = useState(0); // Similar to componentDidMount and componentDidUpdate: useEffect(() => { // Update the document title using the browser API document.title = `You clicked ${count} times`; }); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }
當調用useEffect
的時候,告訴 React 在刷新對 DOM 的更改后運行effect
副作用方法。因為 副作用方法 是在組件中聲明的,因此可以訪問 props 和 state。
默認情況下, React 在每次渲染后執行 effect 方法 —— 包括第一次渲染。想查看和生命周期方法的比較,也可以在 Using the Effect Hool 文檔中找到。
同時 effect 副作用方法可以通過返回函數指定如何 “清理” 它們。例如,下面組件使用效果來訂閱好友的在線 state,並通過取消訂閱來實現清理的目的:
import { 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'; }
在這個示例中,組件卸載或者是由於后面的 re-render 而重新執行副作用方法之前,React 會取消訂閱 ChatAPI
。當然,如果 props 傳過來的 id 是沒有變化的,也可以通過某種方式來跳過訂閱和取消訂閱的行為:https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects
和 useState
一樣,可以在組件中使用多個 useEffect
:
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 方法, 但它們強加了兩個額外的規則:
- 只能在頂層調用 Hooks,不能再循環、條件或者是嵌套方法中調用 Hooks。
- 僅在 React 功能組件中使用 Hooks。不能再常規的 JavaScript 方法中調用 Hook。
React 提供了一個 linter 插件 來自動執行這些規則。雖然這些規則可能會讓開發者比較首先,但是對於 Hooks 的良好運行至關重要。
四、構建自己的 Hook
有時,可能會希望在組件之間重用一些 state 的邏輯,一般之前的做法都是通過高階組件或者是 render props 來解決。自定義 Hook 能夠做到這種需求,而不需要向 tree 中增加更多組件。
前面雖然介紹了 useState
和 useEffect
來訂閱朋友的在線狀態,如果還希望在另一個組件中重用訂閱邏輯,首先需要將這個邏輯提取到一個名為 useFriendStatus
的自定義 Hook 中:
import { 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
,返回的是好友是否在線。
而現在可以在兩個組件中直接使用這個 Hook:
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> ); }
這些組件的狀態是完全獨立的,Hook 是重用有 state 邏輯的一種方式,而不是重用 state 本身。事實上,每次調用 Hook 都會有個完全隔離的狀態。因此可以在一個組件中使用相同的自定義 Hook 兩次。
自定義 Hook 更像是一種約定,而不是一種功能。如果函數的名字以 use
開頭,並且調用了其他的 Hook,則就稱其為一個自定義 Hook。useSomething
命名約定是為了 linter 插件在代碼中查找錯誤。
五、其他的 Hooks
除了上面的 useState
和 useEffect
之外,還有一些其他不太常用的 Hook 也可能很有用。比如 useContext 允許訂閱 React 上下文,不去引入嵌套。
function Example() { const locale = useContext(LocaleContext); const theme = useContext(ThemeContext); // ... }
而 useReducer 允許使用 reducer 管理復雜的組件 state:
function Todos() { const [todos, dispatch] = useReducer(todosReducer); // ...
就簡答的介紹下HOOK吧,在數據請求的時候還是用到很多的