手把手教你用 React Hooks 開發移動端網站,從入門到實踐


React 已經是 JavaScript 生態系統中最受歡迎的前端框架之一。盡管人們已經對它贊不絕口,但 React 團隊仍然在努力讓它變得更好。

在 2018 ReactConf 大會上,React 官方發布了 Hooks,隨后它席卷了整個 React 開發界。

React Hooks 是 React 庫的新增功能,它允許你編寫狀態邏輯並使用其他 React 功能,同時無需編寫類組件。你甚至可以單獨使用 Hooks 來制作自己的應用程序,這對 React 相關的從業者來說是一次重大變革。

image

今天給大家帶來一門 React Hooks 的課程React Hooks 從入門到實踐 ,課程將對 React Hooks 做全方位的分析,並通過純 Hooks 函數組件對 CNode 網站進行移動端頁面的開發,實戰過程中還會介紹前端開發中常用技術棧的使用。

課程實戰用到的技術棧 React + React-Router+ Antd-Mobile + Axios ,實戰部分使用最新 vw 方式做移動端的適配,拋棄 rem 的形式擁抱變化。重寫 Axios 請求庫,做到請求返回統一處理。開發環境的搭建可以作為一個種子項目,方便在工作中啟動新項目時直接使用。

項目效果圖:

image

教程開始:

React 作為 Facebook 推出的前端主流框架之一,在版本升級上一直是采用平滑升級的模式。在升新版本的時候,無論是增加或者刪除了某些 API,React 都能做到版本向后兼容,也就是用舊版本的寫法,最新的 React 包也能做到基本支持。這次也不例外,在 v16.8 版本引入了全新的 API,名叫 React Hooks。引用官方的解釋就是三個點

  • 完全可選的。你無需重寫任何已有代碼就可以在一些組件中嘗試 Hooks。但是如果你不想,你不必現在就去學習或使用 Hooks。
  • 100% 向后兼容的。Hooks 不包含任何破壞性改動。
  • 現在可用。Hooks 已發布於 v16.8.0。

React 官方沒有計划從 React 中移除 Class,但是我相信不久的將來,Hooks 將被大范圍使用。相比之下 Hooks 可以涵蓋所有 Class 組件的應用場景,且提供了更高的靈活性、可測試性和代碼的復用能力。Hooks 不會影響你對 React 概念的理解。恰恰相反,Hooks 為已知的 React 概念提供了更直接的 API:props, state,context,refs 以及生命周期。在后面的章節里,筆者還會一一介紹上面列出的 API。

Dan Abramov 在社交他的社交網站上也毫不吝嗇的給出了他的想法。

image

Hooks 將會是 React 的未來。

我們為什么不再需要 Class 組件

存在即是合理的,React Hooks 要解決的問題是狀態共享,是繼 render-props 和 higher-order components 之后的第三種狀態共享方案,不會產生 JSX 嵌套地獄問題。這個狀態指的是狀態邏輯,所以稱為 狀態邏輯復用會更恰當,因為只共享數據處理邏輯,不會共享數據本身。

在 React Hooks 推出之前,React 便已經有函數組件了,那么已經有了函數組件,為什么開始還要引入 Class 組件呢?

早些時候的 React 組件以有無狀態(state)分為兩種,代碼如下。

// 有狀態組件
class Hello extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      text: 'Hello World'
    }

    render() {
      return <div>{text}</div>
    }
  }
}

// 無狀態組件
// 狀態通過父組件傳入
const Hello = (props) => <div>{props.text}</div>

我們可以通過 Class 組件的 this 上下文去保存和訪問狀態(state),但是函數組件在其作用域內很難維持住這個狀態,試想如果再次運行函數的話,所有的狀態都將被重置。所以我們才一直使用 Class 的形式編寫有狀態組件。

Hooks 編寫函數組件,它的狀態是如何維持的呢

了解過 React Fiber 的同學應該知道,類組件中的狀態其實保存在 Fiber 的屬性 memoizedState 上,並不是在 Class 的 this.state 上。那么回過頭來看 React Hooks 組件的狀態,其實也是去訪問 Fiber 上的 memoizedState 屬性,這樣看來,問題就迎刃而解了。

兩種寫法的對比分析

繁重的寫法。

下面是一段簡單的以 Class 形式書寫的組件代碼。

import React, { Component } from "react";

export default class MyButton extends Component {
  constructor() {
    super();
    this.state = {
      text: "點擊"
    };
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick() {
    this.setState({
      text: "改變"
    });
  }
  render() {
    const { text } = this.state;
    return <button onClick={this.handleClick}>{text}</button>;
  }
}

僅僅是需要一個按鈕組件,代碼量已經接近 20 行之多,可能你會覺得 20 行並不多,但是當組件內部需要控制一些狀態的時候,那代碼量就不僅僅是 20 行這么簡單了。包括整個 React 項目都是由各個組件拼裝而成,層層嵌套,再加上狀態管理插件如 Redux、Mobx 等,就會是一場 “災難”。

反觀 Hooks 的寫法:

import React from "react";

export default const MyButton = () => {
  const [text, setText] = useState('點擊')
  return <button onClick={setText('改變')}>{text}</button>
}

在 Hooks 出現之前,React 也是可以用函數寫組件的,但是只能寫一些無狀態的純組件 (Pure Component) ,也就是內部是不能有屬於自己的狀態變量。上述代碼中 Hooks 實現了函數組件管理自身狀態的方式,不僅在代碼量上得以控制,書寫上也簡便了不少。受限於現代瀏覽器,所有最新 ES6 + 的寫法,不是所有瀏覽器都會支持。類組件的寫法在經過 babel 編譯后會編譯成 ES5 寫法,才能讓各大瀏覽器得以支持和運行。這就導致了編譯后類組件比函數組件多一層繼承 React.Component 的代碼,從這個角度出發,Hooks 寫法降低了編譯后的代碼了減少 bundle 包的大小。

復雜組件變得難以理解。

隨着組件代碼的增多,狀態與狀態緊密相連,想把組件拆分的細致那就變得難上加難。重復的邏輯在不同的組件和生命周期函數之間不斷出現,到那時項目就變得不可維護。

開發環境的搭建

課程總共為 10 章,1 ~ 8 章以實例和原理講解為主,9 ~ 10 章 為實戰章節。

所以 1 ~ 8 章筆者只需要通過官方提供的項目初始化工具 create-react-app 來完成課程內部代碼的講解。

首先電腦里必須事先安裝 Node 環境。

檢測當前 Node 版本和 NPM 版本,執行命令行。

node -v
npm -v

如果已經安裝過的同學會打印出相應的 Node 版本,當然實驗樓也提供了前端的開發環境,內置 Node 和 NPM,已經在全局安裝了 cnpm 包,同學盡量使用 cnpm 安裝 node_modules 包,因為有些包是放在國外的服務器,直接使用 npm 可能會安裝不上或者需要很久的時間,對大家的開發體驗也是不好的。

全局安裝 create-react-app。

cnpm install create-react-app -g

安裝完畢之后,通過指令可以生成項目。

// my-app 為項目文件夾的名字,可自定義
npx create-react-app my-app
or
npm init react-app myapp

初始化項目結束之后,進入進入文件夾,通過 npm run start 啟動項目,默認的端口會是 3000,而實驗樓在線開發環境只對外開放 8080 端口,所以我們要對文件里的腳本做一些改動。

有兩種方式改變 create-react-app 初始化項目的開發環境啟動端口。

  • 修改 package.json 的 scripts 屬性。
"scripts": {
  "start": "PORT=8080 react-scripts start",
  "build": "react-scripts build",
  "test": "react-scripts test",
  "eject": "react-scripts eject"
},

要注意的是,如果是 Windows 用戶建議在 PORT 前加上一個 cross-env,需要通過 cnpm install cross-env -D 下載到開發依賴 devDependencies 中。

cross-env 是一個運行跨平台設置和使用環境變量的腳本 .cross-env 使得您可以使用單個命令,而不必擔心為平台正確設置或使用環境變量。

  • 通過修改 node_modules/react-scripts/scripts/start.js 腳本第 60 行的端口號,如下。
// line 60
const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 8080;

端口修改完之后,點開右邊的 “Web 服務”,會在瀏覽器打開一個在線頁面,如下圖所示。

image

打開瀏覽器,你會遇到如下報錯。

image

原因是實驗樓環境啟動的在線網址是 https 協議,而項目熱更新用的是 ws 協議,所以我們需要將 ws 協議改成 wss 協議。打開項目 node_modules 目錄,找到 node_modules/react-dev-utils/webpackHotDevClient.js 腳本,將第 60 行修改為 wss 如下圖。

image

重新通過 npm run start 啟動項目,再次點開 “Web 服務”,如下圖所示,便是實驗環境配置成功。

image

項目運行的時候有強迫症的同學可以關閉 eslint ,具體方法首先運行指令:

npm run eject

根目錄會多出一個 config 文件夾,進入文件夾打開腳本 webpack.config.js,把 eslint 的配置關閉,如下圖所示

image

將紅框的內容注釋之后,重啟項目,命令行就會不顯示 eslint 語法報錯。

篇幅有限,今天就介紹到這里,對 前端 和 React Hooks 感興趣的同學,歡迎來實驗樓邊敲代碼邊學習~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM