React 入門手冊

React 是目前爲止最受歡迎的 JavaScript 框架之一,而且我相信它也是目前最好用的開發工具之一。

這篇文章的目的在於爲 React 初學者提供一些學習指導。

在學習完這篇文章後,你就可以對 React 有初步的瞭解:

以上這些內容是你構建高級 React 應用的基礎。

這篇文章是專門爲剛接觸 React 的 JavaScript 程序員寫的。現在就讓我們開始學習吧。

什麼是 React?

React 是一個 JavaScript 庫,旨在簡化 UI 的開發。

2013 年,Facebook 首次向全世界發佈了 React。此後,人們用它開發了一些應用最廣泛的 APP,並且它也使 Facebook 和 Instagram 在無數應用中佔得領先地位。

React 最初是爲了使開發者可以在任意時間點都能輕鬆地追蹤 UI 及它的狀態。它通過將 UI 劃分爲多個組件的集合來達到這個目的。

在學習 React 的時候,你可能遇到一些小困難,但是隻要解決了它們,我保證這將會是你最美好的經歷。React 可以使前端開發工作變得更加簡單,而且它的生態裏還有很多好用的庫和工具。

React 自身有一套易於使用的 API,當你開始學習的時候,需要先明白以下 4 個基本概念:

我們將在這篇指導中學習以上幾個基本概念,那些高級的概念我們會留給其它的教程,我也會在文章的末尾給出深入學習 React 的資料。

你可以免費下載 PDF / ePub / Mobi 格式的本篇指導。

學習目錄

學習 React 需要了解多少 JavaScript

在真正開始學習 React 之前,你需要對 JavaScript 的核心概念有很好的理解。

你不需要成爲 JavaScript 專家,但是我希望你對以下內容有很好的瞭解:

如果你對這些概念不熟悉,我爲你提供了一些資料來學習這些概念(點擊文末 “閱讀原文” 可見)。

爲什麼要學習 React?

我強烈建議每一位 Web 開發者都可以對 React 有基本的瞭解。

這是因爲以下幾個原因:

  1. React 十分受歡迎。作爲一名開發者,你很可能在將來參與 React 項目。它們可能是目前正在進行的項目,也可能是你的團隊希望你使用 React 開發的一個全新的 APP。

  2. 現在很多工具都是基於 React 開發的,比如 Next.js,Gatsby 等流行框架與工具,它們在後臺都使用了 React。

  3. 作爲一名前端工程師,你很可能會在面試時遇到關於 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 class>
      <header class>
        <img src={logo} class />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          class
          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 class>
      <header class>
        <img src={logo} class />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          class
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  )
}

export default App

當時我們忽略了 return 語句中的所有內容,但是在本節中我們將會討論它們。

我們將包含在組件返回語句後的括號內的所有內容稱爲 JSX:

<div class>
  <header class>
    <img src={logo} class />
    <p>
      Edit <code>src/App.js</code> and save to reload.
    </p>
    <a
      class
      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 class>
      <header class>
        <img src={logo} class />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <WelcomeMessage />
        <a
          class
          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} class />

我們再來展示一個示例。假設 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 屬性:

<button
  onClick={(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 支持非常多的事件類型,如:onKeyUponFocusonChangeonMouseDownonSubmit 等。

React 組件的生命週期事件

到目前爲止,我們已經學習了怎麼使用 useState 鉤子來管理 state。

在本節中,我想介紹另外一個鉤子:userEffect

useEffect 鉤子允許組件訪問它的生命週期事件。

當你調用這個鉤子時,你需要傳入一個函數。在組件第一次被渲染的時候,以及在隨後的每次重新渲染 / 更新時,React 都會調用這個函數。

React 首先更新 DOM,然後調用任何傳遞給 useEffect() 的函數。

所有這些都不會阻塞 UI 的渲染,即使是同步函數。

這裏是一個示例:

const { useEffect, useState } = React

const 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

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/dXYbZDRSFIJdYAiqFkIL0w