大家好,我是若川。推薦這篇可收藏的React入門手冊。也推薦之前一篇類似的文章《如何使用 React 和 React Hooks 創建一個天氣應用》。
點擊下方卡片關注我、加個星標
React 是目前為止最受歡迎的 JavaScript 框架之一,而且我相信它也是目前最好用的開發工具之一。
這篇文章的目的在于為 React 初學者提供一些學習指導。
在學習完這篇文章后,你就可以對 React 有初步的了解:
什么是 React,它為什么這么受歡迎
如何安裝 React
React 組件
React State
React Props
在 React 中處理用戶事件
React 組件的生命周期事件
以上這些內容是你構建高級 React 應用的基礎。
這篇文章是專門為剛接觸 React 的 JavaScript 程序員寫的。現在就讓我們開始學習吧。
什么是 React?
React 是一個 JavaScript 庫,旨在簡化 UI 的開發。
2013 年,Facebook 首次向全世界發布了 React。此后,人們用它開發了一些應用最廣泛的 APP,并且它也使 Facebook 和 Instagram 在無數應用中占得領先地位。
React 最初是為了使開發者可以在任意時間點都能輕松地追蹤 UI 及它的狀態。它通過將 UI 劃分為多個組件的集合來達到這個目的。
在學習 React 的時候,你可能遇到一些小困難,但是只要解決了它們,我保證這將會是你最美好的經歷。React 可以使前端開發工作變得更加簡單,而且它的生態里還有很多好用的庫和工具。
React 自身有一套易于使用的 API,當你開始學習的時候,需要先明白以下 4 個基本概念:
組件
JSX
State
Props
我們將在這篇指導中學習以上幾個基本概念,那些高級的概念我們會留給其它的教程,我也會在文章的末尾給出深入學習 React 的資料。
你可以免費下載 PDF / ePub / Mobi 格式的本篇指導。
學習目錄
學習 React 需要知道多少 JavaScript
為什么要學習 React
如何安裝 React
React 組件
JSX 簡介
使用 JSX 實現 UI
JSX 與 HTML 的區別
在 JSX 中嵌入 JavaScript
React 中的狀態管理
React 組件中的 Props
React 應用中的數據流
在 React 中處理用戶事件
React 組件中的生命周期事件
參考資料
學習 React 需要了解多少 JavaScript
在真正開始學習 React 之前,你需要對 JavaScript 的核心概念有很好的理解。
你不需要成為 JavaScript 專家,但是我希望你對以下內容有很好的了解:
變量
箭頭函數
使用擴展運算符處理對象和數組
對象和數組的解構
模板字符串
回調函數
ES 模塊化
如果你對這些概念不熟悉,我為你提供了一些資料來學習這些概念(點擊文末“閱讀原文”可見)。
為什么要學習 React?
我強烈建議每一位 Web 開發者都可以對 React 有基本的了解。
這是因為以下幾個原因:
React 十分受歡迎。作為一名開發者,你很可能在將來參與 React 項目。它們可能是目前正在進行的項目,也可能是你的團隊希望你使用 React 開發的一個全新的 APP。
現在很多工具都是基于 React 開發的,比如 Next.js,Gatsby 等流行框架與工具,它們在后臺都使用了 React。
作為一名前端工程師,你很可能會在面試時遇到關于 React 的問題。
這些都是很好的理由,但是我希望你學習 React 的一個主要原因是它真的非常優秀。
React 促成了包括代碼復用、組件化開發在內的幾種很好的開發實踐。它高效、輕量,并且使開發者關注于應用中的數據流,這種開發思想適用于很多常見的場景。
如何安裝 React
有幾種不同的方式安裝 React。
在開始時,我強烈建議一種方法,那就是使用官方推薦的工具:create-react-app
。
create-react-app
是一個命令行工具,旨在讓你快速了解 React。
你可以從使用 npx
開始,這是一種不需要安裝就能下載和執行 Node.js 命令的便捷方法。
在這里查看我的 npx 指南:https://flaviocopes.com/npx/
從 5.2 版的 npm
開始,增加了 npx
命令。如果你現在還沒安裝 npm,那么點擊這里 https://nodejs.org 安裝吧(npm 是隨 Node 安裝的)。
如果你不能確定你的 npm 版本號,那么執行 npm -v
命令來檢查你是否需要更新 npm。
注意:如果你不熟悉終端的使用方法,請訪問 https://flaviocopes.com/macos-terminal/, 查看我的 OSX 終端教程。這份教程適用于 Mac 和 Linux。
當你執行 npx create-react-app <app-name>
命令時,npx
首先會 下載 最新版的 create-react-app
,然后再運行它,運行結束后會把它從你的系統中刪除。
這點很不錯,因為你的系統上永遠不會有舊的版本,并且每次運行的時候,你都會獲得最新、最全的可用版本。
讓我們開始吧:
npx?create-react-app?todolist
運行成功后你會看到:
create-react-app
會在你指定的文件夾下創建項目的目錄結構(本示例中為 todolist
),同時將它初始化為一個 Git 倉庫。
它也會在 package.json
文件中添加幾個命令:
所以你可以即刻進入到新創建的應用目錄下,運行 npm start
命令來啟動 app。
默認情況下,這個命令會在你本地的 3000 端口啟動 app,并打開瀏覽器,為你展示歡迎界面:
現在你就可以開始開發這個應用程序了!
React 組件
在上一節課程里,我們創建了我們的第一個 React 應用。
在這個應用中,包含了一系列執行各種操作的文件,大部分文件都與配置有關,但是有一個文件十分的不同:App.js
。
App.js
是你遇到的 第一個 React 組件。
文件中的代碼如下:
import?React?from?'react'
import?logo?from?'./logo.svg'
import?'./App.css'function?App()?{return?(<div?className="App"><header?className="App-header"><img?src={logo}?className="App-logo"?alt="logo"?/><p>Edit?<code>src/App.js</code>?and?save?to?reload.</p><aclassName="App-link"href="https://reactjs.org"target="_blank"rel="noopener?noreferrer">Learn?React</a></header></div>)
}export?default?App
一個使用 React 或者其他的主流前端框架(如:Vue、Svelte)創建的應用,都是由很多的組件構成的。
不過,我們還是先分析這個組件吧。我把這個組件代碼簡化如下:
import?React?from?'react'
import?logo?from?'./logo.svg'
import?'./App.css'function?App()?{return?/*?something?*/
}export?default?App
現在你可以看到幾件事情:我們使用 import 導入了一些東西,并且 導出 了一個名為 App
的函數。
在這段示例代碼中,我們導入了一個 JavaScript 庫(react
npm 包)、一個 SVG 圖片和一個 CSS 文件。
create-react-app
?設置了一種方法,它允許我們導入圖片和 CSS,然后在 JavaScript 中使用它們。但這不是我們現在需要關心的內容,我們現在關心的是 組件 的概念。
App
是一個官方示例中的函數, 返回了一些初看之下非常怪異的內容。
它看起來很像 HTML,但是內嵌了一些 JavaScript。
其實這就是 JSX,一種我們構建組件時使用的特殊語言。我們將會在下一節討論 JSX。
除了可以返回 JSX,組件還具有一些其他特征。
一個組件可以有它自己的 state(狀態),這就是說它可以封裝一些其他組件無法訪問的屬性,除非它把這些 state 暴露給應用中的其他組件。
一個組件也可以接收來自其他組件的數據,我們稱這些數據為 props。
先不要著急,我們很快就會詳細學習所有的這些概念(JSX,State 和 Props)了。
JSX 簡介
要想學習 React 就必須首先了解 JSX。
在上一節中,我們創建了第一個 React 組件,即 App
,它定義在由 create-react-app
構建的默認應用程序中。
它的代碼如下:
import?React?from?'react'
import?logo?from?'./logo.svg'
import?'./App.css'function?App()?{return?(<div?className="App"><header?className="App-header"><img?src={logo}?className="App-logo"?alt="logo"?/><p>Edit?<code>src/App.js</code>?and?save?to?reload.</p><aclassName="App-link"href="https://reactjs.org"target="_blank"rel="noopener?noreferrer">Learn?React</a></header></div>)
}export?default?App
當時我們忽略了 return
語句中的所有內容,但是在本節中我們將會討論它們。
我們將包含在組件返回語句后的括號內的所有內容稱為 JSX:
<div?className="App"><header?className="App-header"><img?src={logo}?className="App-logo"?alt="logo"?/><p>Edit?<code>src/App.js</code>?and?save?to?reload.</p><aclassName="App-link"href="https://reactjs.org"target="_blank"rel="noopener?noreferrer">Learn?React</a></header>
</div>
這些內容 看起來 很像 HTML,但是卻又不是真正的 HTML。它們之間有一些不同點。
而且將這樣的代碼包含在 JavaScript 文件中有點奇怪:它們看起來一點都不像 JavaScript!
在后臺,React 會處理 JSX,它們會被轉換為瀏覽器可以識別的 JavaScript。
因此,雖然我們編寫了 JSX,但是最終會有一個轉換的步驟,使它可以被 JavaScript 解析器所識別。
React 這樣做的一個主要原因就是:使用 JSX 能更加輕松的開發 UI 界面。
當然了,前提是你必須非常熟悉它。
在下一節中,我們將會學習 JSX 是怎么使 UI 開發變容易的。再然后我們將會討論它與“標準 HTML”的區別,而這些差異是你必須知道的。
使用 JSX 構建 UI
就像上一節中介紹的那樣,JSX 的一個主要作用就是借助它可以非常容易的編寫 UI。
特別的,在 React 組件中,你可以導入其他 React 組件,然后將它們嵌入當前組件以展示它們。
通常情況下,一個文件就是一個 React 組件,這是我們可以非常容易的在其它組件中復用(通過導入的方式)它們的原因。
但是同一個文件中也可以定義其它的 React 組件,這些組件只會在當前文件中用到。這里并沒有明確的規則來規定一個文件中是否需要定義多個組件,選擇最適合你的那種方式即可。
當一個文件中的代碼行數過多時,我通常會將代碼進行拆分,放到單獨的文件中。
為了方便學習,我們在 App.js
文件中再定義一個組件。
我們計劃創建一個名為 WelcomeMessage
的組件:
function?WelcomeMessage()?{return?<p>Welcome!</p>
}
看到了嗎?這個組件就是一個簡單的函數,它返回了一行 JSX,表示一個 p
標簽。
我們將這個函數添加到 App.js
文件中。
現在,我們將 <WelcomeMessage />
添加到 App
組件的 JSX 代碼中,就可以在 UI 中展示這個組件:
import?React?from?'react'
import?logo?from?'./logo.svg'
import?'./App.css'function?WelcomeMessage()?{return?<p>Welcome!</p>
}function?App()?{return?(<div?className="App"><header?className="App-header"><img?src={logo}?className="App-logo"?alt="logo"?/><p>Edit?<code>src/App.js</code>?and?save?to?reload.</p><WelcomeMessage?/><aclassName="App-link"href="https://reactjs.org"target="_blank"rel="noopener?noreferrer">Learn?React</a></header></div>)
}export?default?App
下面是運行結果,你應該可以在屏幕中看到“Welcome!”信息。
我們稱 WelcomeMessage
為子組件,App
為父組件。
我們像使用 HTML 標簽一樣,添加 <WelcomeMessage />
組件。
這就是 React 組件和 JSX 優雅的地方:我們構建應用程序組件,并且像使用 HTML 標簽一樣使用它們。
關于 JSX 與 THML 的區別,我們將會在下一節中學習。
JSX 與 HTML 的區別
JSX 看起來像 HTML,但事實并不是這樣。
在這節課程里,我會介紹一些在使用 JSX 時你必須要知道的東西。
如果你仔細閱讀過 App
組件的 JSX 代碼,會發現一個很明顯的不同點:組件中有一個名為 className
的屬性。
在 HTML 中,我們使用的是 class
屬性。出于各種原因,它可能是使用最廣泛的屬性,而 CSS 就是其中一個原因。class
屬性使我們可以輕松的設置 HTML 樣式,并且在設計 UI 時,Tailwind 之類的 CSS 框架就是以這個屬性為核心的。
但是這里有個問題。我們在 JavaScript 文件中編寫 UI 代碼,而 class
是 JavaScript 語言的保留字,這就意味著我們不能使用它,它有特殊的作用(定義 JavaScript 類)。由于這個原因,React 的作者們不得不選擇一個其它的名稱。
這就是我們為什么用 className
替代了 class
。
當你將一些現有的 HTML 代碼改寫為 JSX 時,需要牢記這點。
React 為了保證頁面能正常顯示,對這種情況進行了特殊處理,但是它會在開發者工具中給出警告:
這種情況非常普遍,并不是只有 HTML 會遇到這種困擾,
JSX 與 HTML 的另一個非常大的不同點是 HTML 是很 寬松。當出現語法錯誤、標簽沒有正確閉合或者匹配時,瀏覽器會盡可能的解析 HTML,而不是中斷解析過程。
這是 Web 的一個核心特點,它非常寬松。
但是 JSX 并不寬松。如果你忘記將一個標簽閉合,你將會得到一條錯誤信息:
React 會給出非常友好的錯誤信息,使你可以準確地定位問題并解決問題。
第三個 JSX 與 HTML 的不同點在于:在 JSX 中,我們可以內嵌 JavaScript。
我們會在下一節討論這點。
在 JSX 嵌入 JavaScript
React 的一大特點就是我們可以非常容易的在 JSX 中嵌入 JavaScript。
其他的前端框架(如 Angular 和 Vue)有自己的特殊方法來在模板中顯示 JavaScript 值,或者執行類似循環的操作。
React 并沒有添加類似的新特性。React 通過使用大括號的方式,容許我們在 JSX 中嵌入 JavaScript。
我們展示的第一個示例,來自于我們之前學習過的 App
組件。
我們可以使用下面的方法導入 logo
的 SVG 文件:
import?logo?from?'./logo.svg'
然后在 JSX 中,我們將這個 SVG 文件賦值給 img
標簽的 src
屬性。
<img?src={logo}?className="App-logo"?alt="logo"?/>
我們再來展示一個示例。假設 App
組件有一個變量,名為 message
:
function?App()?{const?message?=?'Hello!'//...
}
我們可以通過在 JSX 的任意位置添加 {message}
,來在 JSX 中顯示這個變量的值。
我們可以在 { }
中添加任何 Javscript 表達式,但是每對大括號中只能有 一個 表達式,并且這個表達式必須是可正確求值的。
如下所示,這是一個在 JSX 中非常常見的表達式。我們編寫了一個三元運算符,在其中定義了一個條件語句(message === 'Hello!'
),當條件為真時,我們輸出一個值(The message was "Hello!"
);條件為假時,輸出另一個值(當前示例中為變量 message
的值):
{message?===?'Hello!'???'The?message?was?"Hello!"'?:?message
}
在 React 中管理 state
每一個 React 組件都可以有它自己的 state。
那么什么是 state ?state 就是 由組件管理的狀態的集合。
例如,對于表單來說,它的每一個獨立的 input 元素都管理著它自己的 state:它的輸入值。
一個按鈕負責處理自己是否被點擊;是否獲得焦點。
一個鏈接負責管理鼠標是否懸停在它上面。
在 React 或者其他組件化的框架、庫中,我們所有的應用都是以大量使用含有 state 的組件為基礎構建的。
我們使用由 React 提供的高效管理工具 useState
來管理 state。從技術上來說,它是個 鉤子 (盡管事實就是這樣,但是現在我們還不需要知道鉤子的詳細信息)。
你可以使用下面的方法來從 React 中導入 useState
:
import?React,?{?useState?}?from?'react'
通過調用 useState()
,我們將會得到一個 state,以及一個供我們調用,用來修改 state 值的函數。
useState()
可以傳入一個參數,用來初始化 state。它會返回一個數組,這個數組包含一個 state 和一個修改 state 值的函數。
如下所示:
const?[count,?setCount]?=?useState(0)
這一點非常重要。我們不能直接修改 state,只能通過調用修改函數來修改它,否則,React 組件無法及時將數據的變化反映在 UI 中。
調用修改函數是一種將組件 state 的變化告知 React 的方法。
這個語法是不是看起來有點奇怪?這是因為 useState()
返回的是數組,所以我們使用了數組解構的方法來獲取每個數組成員,就像這樣:const [count, setCount] = useState(0)
下面是一個示例:
import?{?useState?}?from?'react'const?Counter?=?()?=>?{const?[count,?setCount]?=?useState(0)return?(<div><p>You?clicked?{count}?times</p><button?onClick={()?=>?setCount(count?+?1)}>Click?me</button></div>)
}ReactDOM.render(<Counter?/>,?document.getElementById('app'))
我們也可以調用多次調用 useState()
,來創建多個 state:
const?[count,?setCount]?=?useState(0)
const?[anotherCounter,?setAnotherCounter]?=?useState(0)
React 組件中的 Props
我們稱傳入組件的初始值為 props。
我們之前創建了一個 WelcomeMessage
組件:
function?WelcomeMessage()?{return?<p>Welcome!</p>
}
我們這樣使用它:
<WelcomeMessage?/>
這個組件沒有任何初始值,所以它沒有 props。
在 JSX 中,props 可以作為屬性傳給組件。
<WelcomeMessage?myprop={'somevalue'}?/>
在組件中,我們以函數參數的形式接收 props:
function?WelcomeMessage(props)?{return?<p>Welcome!</p>
}
通常情況下,我們用對象解構的形式來獲取 props 的名稱:
function?WelcomeMessage({?myprop?})?{return?<p>Welcome!</p>
}
現在我們獲得了 props,并可以在組件中使用它了。如下所示,我們可以在 JSX 中輸出它的值:
function?WelcomeMessage({?myprop?})?{return?<p>{myprop}</p>
}
這里的大括號有多種含義。對于函數參數來說,大括號是對象解構語法的一部分。我們也可以用它來定義函數代碼塊;而在 JSX 中,我們用它來輸出 JavaScript 值。
將 props 傳遞給組件是一種在應用中傳遞值的好方法。
一個組件既可以有自己的狀態(state),也可以通過 props 來接收數據。
當將函數作為 props 時,子組件就可以調用父組件中定義的函數。
有一種被稱為 children
的特殊 props,它代表了包含在組件的開始標簽和結束標簽之間的所有內容,例如:
<WelcomeMessage>?Here?is?some?message?</WelcomeMessage>
這種情況下,在 WelcomeMessage
中,我們可以通過使用名為 children
的 props 來獲取 Here is some message
。
function?WelcomeMessage({?children?})?{return?<p>{children}</p>
}
React 應用中的數據流
在一個 React 應用中,數據通常以 props 的方式從父組件流向子組件,就像我們在上一節看到的那樣:
<WelcomeMessage?myprop={'somevalue'}?/>
如果給子組件傳遞一個函數,你就可以在子組件中修改父組件的 state:
const?[count,?setCount]?=?useState(0)<Counter?setCount={setCount}?/>
如下所示,在 Counter 組件內部,我們取得了 setCount
,然后在適當情況下,可以調用它來修改父組件中的 count
:
function?Counter({?setCount?})?{//...setCount(1)//...
}
其實還有很多更高級的方法來管理數據,比如 Context API 和 Redux 之類的庫。但是這些方法會增加復雜性,而在大約 90% 的時間里,我們剛剛介紹的兩種方法都是完美的解決方案。
在 React 中處理用戶事件
React 提供了一種簡單的方法來管理從 DOM 觸發的事件,如點擊事件、表單事件等。
這里我們以最容易理解單擊事件為例來進行說明。
你可以在任意的 JSX 元素上使用 onClick
屬性:
<buttononClick={(event)?=>?{/*?handle?the?event?*/}}
>Click?here
</button>
每當元素被點擊的時候,傳遞給 onClick
屬性的函數就會被觸發。
你也可以在 JSX 的外部定義這些函數:
const?handleClickEvent?=?(event)?=>?{/*?handle?the?event?*/
}function?App()?{return?<button?onClick={handleClickEvent}>Click?here</button>
}
當點擊 button 時,就會觸發 click
事件,此時,React 就會調用 click
事件的處理函數。
React 支持非常多的事件類型,如:onKeyUp
,onFocus
,onChange
,onMouseDown
,onSubmit
等。
React 組件的生命周期事件
到目前為止,我們已經學習了怎么使用 useState
鉤子來管理 state。
在本節中,我想介紹另外一個鉤子:userEffect
。
useEffect
鉤子允許組件訪問它的生命周期事件。
當你調用這個鉤子時,你需要傳入一個函數。在組件第一次被渲染的時候,以及在隨后的每次重新渲染 / 更新時,React 都會調用這個函數。
React 首先更新 DOM,然后調用任何傳遞給 useEffect()
的函數。
所有這些都不會阻塞 UI 的渲染,即使是同步函數。
這里是一個示例:
const?{?useEffect,?useState?}?=?Reactconst?CounterWithNameAndSideEffect?=?()?=>?{const?[count,?setCount]?=?useState(0)useEffect(()?=>?{console.log(`You?clicked?${count}?times`)})return?(<div><p>You?clicked?{count}?times</p><button?onClick={()?=>?setCount(count?+?1)}>Click?me</button></div>)
}
因為在隨后的每次重新渲染 / 更新時,傳遞給 useEffect() 的函數都會被執行,所以出于性能上的考慮,我們可以告訴 React 在某些時候不要執行這個函數。為了實現這個目的,我們可以為 useEffect() 傳入第二個參數,這個參數是一個數組,它的成員是需要監視的 state 變量。只有在這些 state 發生變化的時候,React 才會執行這個函數。
useEffect(()?=>?{console.log(`Hi?${name}?you?clicked?${count}?times`)
},?[name,?count])
類似的,你可以傳入一個空數組,這會使 React 只在組件掛載的時候才執行這個函數。
useEffect(()?=>?{console.log(`Component?mounted`)
},?[])
這是一個非常有用的技巧。
useEffect() 非常適合添加日志,訪問第三方 API 等。
接下來做什么?
熟練掌握在這篇文章中提到主題是朝著學習 React 目標邁出的重要一步。
在這里我想給出一些指導,防止你在有關 React 教程和課程的海洋中迷失方向。
接下來該學習什么呢?
了解有關虛擬 DOM,編寫聲明式代碼,單向數據流,不變性,組合的更多理論。
構建一些簡單的 React 應用。例如:一個簡單的計數器或者與公共 API 交互。
學習如何使用條件渲染,如何在 JSX 中使用循環,如何使用 React 開發者工具
通過 plain CSS 或者 Styled Components 學習如何在 React 應用中使用 CSS。
學習如何使用 Context API,useContext 與 Redux 來管理 state。
學習如何與 forms 交互。
學習如何使用 React 路由。
學習如何測試 React 應用。
了解基于 React 構建的應用程序框架,如 Gatsby 或者 Next.js。
當然,最重要的是,請確保在構建應用的過程中實踐你所學習的每一個知識點。
結語
非常感謝閱讀這篇入門指導。
我希望這篇指導可以激發你去學習更多關于 React 知識的興趣以及了解 React 能做的每一件事。
不要忘了你可以免費下載 PDF / ePub / Mobi 格式的本篇指導
每天我都會在我的網站 flaviocopes.com 上發布編程教程,你可以在那里看到更多類似的精彩內容。
原文鏈接:https://www.freecodecamp.org/news/react-beginner-handbook/
作者:Flavio Copes
譯者:xinlei_ye
最近組建了一個江西人的前端交流群,如果你是江西人可以加我微信 ruochuan12 拉你進群。
今日話題
時光飛逝,明天就是端午節三天假期了,提前祝大家端午安康。歡迎分享、收藏、點贊、在看我的公眾號文章~
一個愿景是幫助5年內前端人走向前列的公眾號
可加我個人微信?ruochuan12,長期交流學習
推薦閱讀
我在阿里招前端,我該怎么幫你(可進模擬面試群)
2年前端經驗,做的項目沒技術含量,怎么辦?
點擊上方卡片關注我、加個星標
·················?若川簡介?·················
你好,我是若川,畢業于江西高校。現在是一名前端開發“工程師”。寫有《學習源碼整體架構系列》多篇,在知乎、掘金收獲超百萬閱讀。
從2014年起,每年都會寫一篇年度總結,已經寫了7篇,點擊查看年度總結。
同時,活躍在知乎@若川,掘金@若川。致力于分享前端開發經驗,愿景:幫助5年內前端人走向前列。