《React Native 精解與實戰》書籍連載「React Native 底層原理」


截圖

此文是我的出版書籍《React Native 精解與實戰》連載分享,此書由機械工業出版社出版,書中詳解了 React Native 框架底層原理、React Native 組件布局、組件與 API 的介紹與代碼實戰,以及 React Native 與 iOS、Android 平台的混合開發底層原理講解與代碼實戰演示,精選了大量實例代碼,方便讀者快速學習。

書籍還配套了視頻教程「80 節實戰課精通 React Native 開發」,此視頻課程建議配合書籍學習,書籍中原理性的東西講解的比較清晰,而視頻教程對於組件、API 等部分的代碼實戰開發講解比較直觀。

書籍相關所有資料請訪問:http://rn.parryqiu.com


本章將深入講解 React Native 的底層原理,萬丈高樓平地起,非常深入地理解 React Native 底層的實現,在你開發或遇到難題調試時非常有幫助。
此部分包含 React Native 的框架構成、工作原理、UI 層的渲染與重繪以及組件間通信、React Native 與各個平台的通信實現以及 React Native 中的生命周期。
如果需要直接開始 React Native 的開發與實戰,請直接跳至第四章開始學習。

3.1 React Native 框架構成

React Native 框架內部已提供了很多的內置組件,如圖 3-1 所示。如 View、Text 等基本組件,用於一些功能布局的 Button、Picker 等,用於列表展示的各種 List 組件和對應 iOS 平台與 Android 平台的特定組件、API 等。同時也提供了供編寫與原生平台交互的接口,在后續的章節我們會進行與原生平台的混合實戰開發實戰。
截圖
圖 3-1 React Native 框架構成

3.2 React Native 工作原理

在 React 框架介紹的章節,我們理解了如何將代碼渲染至虛擬 DOM 並更新到真實 DOM 的過程。在 React Native 框架中,渲染到 iOS 平台與 Android 平台的過程如圖 3-2 所示。
截圖
圖 3-2 React Native 渲染
在 React 框架中,JSX 源碼通過 React 框架最終渲染到了瀏覽器的真實 DOM 中,而在 React Native 框架中,JSX 源碼通過 React Native 框架編譯后,通過對應平台的 Bridge 實現了與原生框架的通信。如果我們在程序中調用了 React Native 提供的 API,那么 React Native 框架就通過 Bridge 調用原生框架中的方法。
因為 React Native 的底層為 React 框架,所以如果是 UI 層的變更,那么就映射為虛擬 DOM 后進行 diff 算法,diff 算法計算出變動后的 JSON 映射文件,最終由 Native 層將此 JSON 文件映射渲染到原生 App 的頁面元素上,最終實現了在項目中只需要控制 state 以及 props 的變更來引起 iOS 與 Android 平台的 UI 變更。
編寫的 React Native代碼最終會打包生成一個 main.bundle.js 文件供 App 加載,此文件可以在 App 設備本地,也可以存放於服務器上供 App 下載更新,后續章節講解的熱更新就會涉及到 main.bundle.js 位置的設置問題。

3.3 React Native 與原生平台通信

在與原生框架通信中,如圖 3-3 所示,React Native 采用了 JavaScriptCore 作為 JS VM,中間通過 JSON 文件與 Bridge 進行通信。而如果在使用 Chrome 瀏覽器進行調試時,那么所有的 JavaScript 代碼都將運行在 Chrome 的 V8 引擎中,與原生代碼通過 WebSocket 進行通信。
截圖
圖 3-3 React Native 與原生平台的通信
關於 React Native 框架與原生平台的通信原理的詳細介紹,后續的混合開發章節將會有詳細的講解與實戰開發。

3.4 組件間通信

React Native 開發最基本的元素就是組件,React Native 與 React 一樣,也會涉及到組件之間的通信,用於數據在組件之間的傳遞,下面列出了幾種常用的組件間通信的方式。

父子組件的通信

如同之前的章節介紹 React 組件間傳遞參數一樣,在 React Native 中,父組件向子組件傳遞值,可以通過 props 的形式。
在下例中,父組件通過調用子組件並賦值子組件的 name 為 React,子組件通過 this.props.name 獲取父組件傳遞過來的 name 的字符串值 React。
完整代碼在本書配套源碼的 03-04 文件夾。

/**
* 章節: 03-04
* 父子組件通信,在父組件中調用子組件
* FilePath: /03-04/parent-2-child.js
* @Parry
*/

<ChildComponent name='React'/>

/**
* 章節: 03-04
* 子組件實現,通過 props 獲取父頁面傳遞的值
* FilePath: /03-04/parent-2-child.js
* @Parry
*/

class ChildComponent extends Component {
    render() {
        return (
          <Text>Hello {this.props.name}!</Text>
        );
    }
}

子父組件的通信

在開發過程中,不僅有父子之間的通信,有時還會有子組件向父組件通信傳遞值的需求,比如當子組件的某個值變更后,需要通知到父組件做相應的變更與響應,那么就會需要子父組件之間的通信。
示例代碼如下,在父組件的定義中,在調用子組件時,同樣向子組件傳遞了一個參數,不過這個參數是一個函數,此函數用於接收后續子組件向父組件傳遞過來的數據,與之前父組件向子組件傳遞數據不太一樣。
完整代碼在本書配套源碼的 03-04 文件夾。

/**
* 章節: 03-04
* 子父組件通信,父組件的實現
* FilePath: /03-04/child-2-parent.js
* @Parry
*/
import React, {Component} from 'react';
import ChildComponent from './ChildComponent'

class App extends Component {
  constructor(props) {
    super(props)
    this.state = {
      name: 'React'
    }
  }

  //傳遞到子組件的參數,不過參數是一個函數。
  handleChangeName(nickName) {
    this.setState({name: nickName})
  }

  render() {
    return (
      <div>
        <p>父組件的 name:{this.state.name}</p>
        <ChildComponent
          onChange={(val) => {
          this.handleChangeName(val)
        }}/>
      </div>
    );
  }
}

export default App;

下面為子組件的定義,子組件在頁面中定義了一個按鈕,點擊此按鈕后,調用自身的一個函數 handleChange,修改了自身 state 中的值 name 為 nickName 定義的值 Parry,那么此子組件的頁面上的字符串將由之前的 Hello React! 變為 Hello Parry!,同時使用了 this.props.changeName,也就是父組件調用時傳遞過來的函數,向父組件傳遞了 nickName 的值 Parry。
父組件在接收到子組件的調用后,調用了父組件自身的函數 handleChangeName 修改了自身的 state 中的 name 的值為 Parry,也就是子組件傳遞過來的 Parry,所以同時,父組件的頁面上的值也同時由之前的 React 變更成了 Parry。

/**
* 章節: 03-04
* 子父組件通信,子組件的實現
* FilePath: /03-04/child-2-parent.js
* @Parry
*/

import React, {Component} from 'react'

export default class ChildComponent extends Component {
  constructor(props) {
    super(props)

    this.state = {
      name: 'React'
    }
  }

  handleChange() {
    const nickName = 'Parry';
    this.setState({name: nickName})
    //調用父組件傳遞過來的函數參數,傳遞值到父組件去。
    this
      .props
      .changeName(nickName)
  }

  render() {
    const {name} = this.state;
    return (
      <div>
        <p>Hello {name}!</p>
        <Button
          onPress={this
          .handleChange
          .bind(this)}
          title="修改一下 name 為 Parry"/>
      </div>
    )
  }
}

多級組件之間的通信

如果組件之間的父子層級非常多,需要進行組件之間的傳遞,這時候當然可以通過上面介紹的方法進行一級一級的傳遞,但是當這種組件間層級很深的時候,這樣的傳遞方法不是一個太好的方法。
解決的方法是首先要在設計 App 時,需要注意不能讓組件之間的層級關系太深,一是為了避免組件之間通信的冗長,還有一個原因是太深的嵌套邏輯,用戶體驗上也不會很好,可以想象一下用戶從最底層一層層操作返回到最頂層時的體驗。
第二就是可以使用如 context 對象或 global 等方式進行多級組件間的通信,但是這種方式不推薦。

無直接關系組件間通信

前面提到的都是有層級關系的組件間的通信方式,而如果組件間沒有層級的關系的話,可以通過如 AsyncStorage 或 JSON 文件等方式進行無直接關系組件間的通信。
當然,還可以使用 EventEmitter / EventTarget / EventDispatcher繼承或實現接口的方式、Signals 模式或 Publish / Subscribe 的廣播形式,都可以達到無直接關系組件間的通信。
這些組件間的通信方式使得組件之間的數據可以傳遞起來,后續的實戰章節會有詳細的代碼實現,這里主要進行了理論部分的介紹。掌握這部分知識后才可以將 App 開發中的基本單位,也就是組件串聯起來。


截圖


免責聲明!

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



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