概述
hooks 是一個讓你在不使用類的狀況下還能使用state和別的一些react功能的新功能(React v16.7.0-alpha版本)html
hooks是向後兼容的,這篇文章給有React使用經驗的小夥伴提供了一個概述。react
下面這個例子定義了一個計數器,當點擊按鈕的時候。計數器就會加1數組
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,咱們在函數裏面調用它來添加一些局部的狀態。react在從新渲染的時候保存這個狀態值,
useState 返回了一個狀態值(count)和一個能改變狀態值的函數(setCount),你可一再事件或者別的地方來調用這個函數。它除了沒有把新的狀態值和舊的狀態值合併之外別的和class裏面的this.setState()都很類似(這裏有個例子比較useState和this.state())
useState 惟一的參數是初始化的值。就像上面的例子中,初始化的值是0。
注意:和this.state不同、這裏的state你沒必要非得定義成一個對象。固然你也能夠把它定義成一個對象,初始值只會在第一次被渲染的時候用到函數
定義多個狀態變量ui
你能夠在單個組件裏屢次使用State hookthis
function ExampleWithManyStates() { // 定義多個state變量 const [age, setAge] = useState(42); const [fruit, setFruit] = useState('banana'); const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]); // ... }
數組的解構語法可讓你在調用useState的時候給satate變量定義不一樣的名字,這些名字不是useState API的一部分。相反的,React假設你每一次渲染的時候屢次調用了useState,而每次渲染都是相同的順序執行.咱們會回想一下爲何這樣作,當這對之後有用spa
什麼是Hook
鉤子是容許從功能組件(function component)「掛鉤」React狀態和生命週期功能的功能。鉤子在類內部不起做用 - 它讓你在不依賴類的去狀況下使用React(咱們不推薦你立刻重寫已經存在的組件,可是你能夠嘗試在新的組件裏使用Hook)
React 提供了一些內置的Hooks,好比useState。你也能夠建立本身的Hooks以在不一樣組件中重用插件
Effect Hook
你以前多是從React組件裏執行數據提取,訂閱或手動更改DOM。咱們將這些操做稱爲「函數反作用」(或簡稱爲「效果」),由於它們會影響其餘組件,而且沒法在渲染過程當中完成。
Effect Hook中的useEffect增長了在功能組件函數反作用的功能。它與React類中的componentDidMount,componentDidUpdate和componentWillUnmount具備相同的目的,可是將這些鉤子統一爲單個API。(useEffect與Class鉤子函數比較。)code
例如,組件在React更新了Dom後設置了文檔標題component
import { useState, useEffect } from 'react'; function Example() { const [count, setCount] = useState(0); // 和componentDidMount ,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'函數,Effects 被定義在組建內容, 這樣就能夠訪問到組件的props和state,默認狀況下,React每一次執行render後(包括第一次render)都會執行effects(進一步討論useEffect和Class生命週期的比較)
Effects也能夠指定返回函數來清理狀態,下面這個例子,組件使用effect 訂閱了好友的在線狀態,又經過unsubscribing 來清理狀態。(Effects的返回函數至關於componentwillmount)
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'; }
在這個例子裏面,當組件將被卸載以及從新運行effect致使的渲染以前,React會取消對ChatApi的訂閱(若是有須要,在props.friend.id的值沒有改變的狀況下, 咱們能夠告訴React跳太重新訂閱)
就像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的拆分
鉤子是js函數,但它們加入了兩個額外的規則:
構建你本身的Hooks
有的時候,咱們但願在組件之間重用一些有狀態邏輯。通常來講,這個問題有兩種流行的解決辦法:高階組件和render props。Custom Hooks容許你執行這樣的操做,而且不須要在代碼樹中添加更多組件。
在文章的早些部分,咱們介紹了一個FriendStatus 組件調用useState和useEffect Hooks來訂閱朋友的在線狀態。若是咱們還想要在另外一個組件中重用此訂閱邏輯。
首先,咱們將這個邏輯提取到一個名爲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 做爲參數,而後返回咱們的朋友是否在線。
如今咱們就能夠在下面的兩個組件中使用它
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> ); }
這些組件的狀態是徹底獨立的,Hooks是重用狀態邏輯的一種方式,而不是狀態自己。事實上,每一次Hook調用都是一個徹底單獨的狀態 - 因此你甚至能夠在一個組件中屢次定義一個相同的Hook。
custom hook更像是一種慣例而非功能。若是函數的名字以use開頭而且它調用其餘Hook,咱們就稱它爲一個Custom Hook。useSomething命管理是linter插件如何使用Hooks在代碼中查找錯誤。
Other Hooks
你可能會發現一些不多用的內置Hook頗有用。例如,useContext容許訂閱React上下文而不引入嵌套:
function Example() { const locale = useContext(LocaleContext); const theme = useContext(ThemeContext); // ... }
useReducer容許使用reducer管理複雜組件的本地狀態:
function Todos() { const [todos, dispatch] = useReducer(todosReducer); // ...
下一步
從 State Hook 文開始吧