前端之React實戰:建立跨平臺的專案架構

王下邀月熊_Chevalier發表於2015-11-12

本篇為翻譯文章,原文地址這裡

React/React Native一個很受歡迎的地方在於它能夠在不同平臺之間共享業務邏輯,在看完 Desktop, Mobile, and Web app in one project這個專案之後筆者就開始思考應該如何組織專案結構,能夠使其在web、desktop(Electron)以及mobile應用之間儘可能地共用相同的程式碼基礎,並且保證能在以後的專案中擴充套件到其他平臺。

檔案索引

首先需要認識到在mobile專案與web/desktop專案中最大的程式碼區別在render()函式中,換言之,我們所需要做的工作就是將render函式抽象出來,以允許具體平臺的工程可以使用正確的程式碼。

要做到這一點,最簡單的方式就是利用React Native的一個內部特性,即在使用import/require匯入檔案時:

import File from `./File`;  

React Native的打包器會首先尋找 File.<platform>.js檔案,然後再去尋找File.js。這就允許我們將Android平臺的程式碼放置到 File.android.js, iOS 的放入到File.ios.js, 以及Web平臺的程式碼放入到 File.js, 而不需要改變匯入的宣告 ./File

Render獨立於Component

這種方式適合於可以在多個平臺之間共享複雜狀態與邏輯程式碼的情況下,當然,在該示例中有點過於複雜了。不過筆者認為在實際專案中的作用還是不言自明的。

基礎的元件如下所示:

class Hello extends Component {  
    constructor(props) {
       super(props);
    }
    render() {
        // Code to render a container with 
        // "Hello, {props.name}" inside of it
    }
}

在web專案中,Render函式如下所示:

render() {  
    return (<div>Hello, {this.props.name}</div>);
}

而在移動端專案中,Render函式可能如下所示:

render() {  
    return (<View>
        <Text>Hello, {this.props.name}</text>
    </View>);
}

那麼整個專案的結構如下所示:

- index.js
- index.ios.js
- index.android.js
- src/
-- Hello.js
-- HelloRender.js
-- HelloRender.android.js

接下來將各個獨立的渲染函式和它們的依賴放置到各自的檔案中:

// HelloRender.js
import React from `react`;

export default function (props) {  
    // we would like a pure function, for easy testing
    return (<div>Hello, {props.name}</div>);
}

// HelloRender.android.js
import React, {View, Text} from `react-native`;

export default function (props) {  
    return (<View>
        <Text>Hello, {props.name}</text>
    </View>);
}

最終在我們的Hello.js檔案中:

// This will import our platform-specific render function
import Render from `./HelloRender`;

class Hello extends Component {  
    constructor(props) {
        super(props);
    }

    render() {
        // Now we call our render function,
        // bound to the context of our component
        // In this case we`re only using component props,
        // but later we may desire to access the state or
        // other methods on the component.
        return Render.call(this, this.props, this.state);
    }
}

注意,雖然我們是針對不同平臺使用了不同的渲染函式,但是還是可以共享很多的邏輯控制程式碼。

Component與模組衝突

上文中一直沒有提及一件事,就是應該在哪邊引入React / React Native提供的官方的元件,譬如通用的Component這個類。在最新的React v0.14中是分成了react與react-dom兩個部分,它的設計思想在於通常的應用只要匯入react的模組即可,而在特殊需要的時候可以選擇性地匯入react-native的模組,不過筆者在自己的試驗中沒發現這樣的解決方法,因此還是決定用類似於上文提及的抽象render函式的方法。我們需要建立兩個新的檔案:

- index.js
- index.android.js
- src/
-- Component.js
-- Component.android.js
-- Hello.js
-- HelloRender.js
-- HelloRender.android.js

接下來,我們需要根據平臺正確地匯入不同的元件,即在新檔案中:

// Component.js
export {Component} from `react`;  

// Component.android.js
export {Component} from `react-native`;  

最後,在我們的Hello.js這個統一的檔案中:

// import platform-specific component class
import {Component} from `./Component`;

class Hello extends Component ...  

好了,到這裡一個完整的跨平臺的構建應該是完成了。

相關文章