<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
這個例子用來顯示一個計數器。當你點選按鈕,計數器的值就會增加:
import React, { useState } from 'react'; function Example() { // 宣告一個叫 「count」 的 state 變數。 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 會在重複渲染時保留這個 state
。useState
會返回一對值:當前狀態和一個讓你更新它的函數,你可以在事件處理常式中或其他一些地方呼叫這個函數。它類似 class
元件的 this.setState
,但是它不會把新的 state
和舊的 state
進行合併。(我們會在使用 State Hook 裡展示一個對比 useState
和 this.state
的例子)。
useState
唯一的引數就是初始 state
。在上面的例子中,我們的計數器是從零開始的,所以初始 state
就是 0
。值得注意的是,不同於 this.state
,這裡的 state
不一定要是一個物件 —— 如果你有需要,它也可以是。這個初始 state
引數只有在第一次渲染時會被用到。
你可以在一個元件中多次使用 State Hook:
function ExampleWithManyStates() { // 宣告多個 state 變數! const [age, setAge] = useState(42); const [fruit, setFruit] = useState('banana'); const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]); // ... }
陣列解構的語法讓我們在呼叫 useState
時可以給 state
變數取不同的名字。當然,這些名字並不是 useState
API 的一部分。React 假設當你多次呼叫 useState
的時候,你能保證每次渲染時它們的呼叫順序是不變的。後面我們會再次解釋它是如何工作的以及在什麼場景下使用。
Hook 是一些可以讓你在函陣列件裡 " 鉤入" React state
及生命週期等特性的函數。Hook 不能在 class
元件中使用 —— 這使得你不使用 class
也能使用 React。(我們不推薦把你已有的元件全部重寫,但是你可以在新元件裡開始使用 Hook。)
React 內建了一些像 useState
這樣的 Hook。你也可以建立你自己的 Hook 來複用不同元件之間的狀態邏輯。我們會先介紹這些內建的 Hook。
你之前可能已經在 React 元件中執行過資料獲取、訂閱或者手動修改過 DOM。我們統一把這些操作稱為“副作用”,或者簡稱為“作用”。
useEffect
就是一個 Effect Hook,給函陣列件增加了操作副作用的能力。它跟 class
元件中的 componentDidMount
、componentDidUpdate
和 componentWillUnmount
具有相同的用途,只不過被合併成了一個 API。
例如,下面這個元件在 React 更新 DOM 後會設定一個頁面標題:
import React, { useState, useEffect } from 'react'; function Example() { const [count, setCount] = useState(0); // 相當於 componentDidMount 和 componentDidUpdate: useEffect(() => { // 使用瀏覽器的 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 的更改後執行你的“副作用”函數。由於副作用函數是在元件內宣告的,所以它們可以存取到元件的 props
和 state
。預設情況下,React 會在每次渲染後呼叫副作用函數 —— 包括第一次渲染的時候。
副作用函數還可以通過返回一個函數來指定如何“清除”副作用。例如,在下面的元件中使用副作用函數來訂閱好友的線上狀態,並通過取消訂閱來進行清除操作:
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'; }
在這個範例中,React 會在元件銷燬時取消對 ChatAPI
的訂閱,然後在後續渲染時重新執行副作用函數。(如果傳給 ChatAPI
的 props.friend.id
沒有變化,你也可以告訴 React 跳過重新訂閱。)
跟 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); } // ...
通過使用 Hook,你可以把元件內相關的副作用組織在一起(例如建立訂閱及取消訂閱),而不要把它們拆分到不同的生命週期函數裡。
Hook 就是 JavaScript 函數,但是使用它們會有兩個額外的規則:
有時候我們會想要在元件之間重用一些狀態邏輯。目前為止,有兩種主流方案來解決這個問題:高階元件和 render props
。自定義 Hook 可以讓你在不增加元件的情況下達到同樣的目的。
前面,我們介紹了一個叫 FriendStatus
的元件,它通過呼叫 useState
和 useEffect
的 Hook 來訂閱一個好友的線上狀態。假設我們想在另一個元件裡重用這個訂閱邏輯。
首先,我們把這個邏輯抽取到一個叫做 useFriendStatus
的自定義 Hook 裡:
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
是完全獨立的。Hook 是一種複用狀態邏輯的方式,它不復用 state
本身。事實上 Hook 的每次呼叫都有一個完全獨立的 state
—— 因此你可以在單個元件中多次呼叫同一個自定義 Hook。
自定義 Hook 更像是一種約定而不是功能。如果函數的名字以 use
開頭並呼叫其他 Hook,我們就說這是一個自定義 Hook。 useSomething
的命名約定可以讓我們的 linter
外掛在使用 Hook 的程式碼中找到 bug。
你可以建立涵蓋各種場景的自定義 Hook,如表單處理、動畫、訂閱宣告、計時器,甚至可能還有更多我們沒想到的場景。我們很期待看到 React 社群會出現什麼樣的自定義 Hook。
除此之外,還有一些使用頻率較低的但是很有用的 Hook。比如,useContext
讓你不使用元件巢狀就可以訂閱 React 的 Context。
function Example() { const locale = useContext(LocaleContext); const theme = useContext(ThemeContext); // ... }
另外 useReducer
可以讓你通過 reducer
來管理元件原生的複雜 state
。
function Todos() { const [todos, dispatch] = useReducer(todosReducer); // ...
本篇文章就到這裡了,希望能夠給你帶來幫助,也希望您能夠多多關注it145.com的更多內容!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45