前端和React Native程式碼互轉總結

點燃火焰發表於2018-03-02

React Native出現的目的本就是“learn once, write anywhere”,Facebook希望人們能夠學習一次,到處使用,但是同樣是JS程式碼,從前端移植到RN,或者RN移植到前端,卻並沒有想象的那麼容易。事實上除了語法相同外,還有很多不一樣的地方,導致我們沒法做到直接copy,以下是我在做遷移程式碼的時候,總結的一些經驗

1 Antd Mobile

Antd Mobile的螞蟻金服開源的一套UI元件,已經實現了前端、iOS、Android的三端統一UI,推薦大家多多使用

1.1 Flex

1.1.1 使用Flex的引數

多用direction justify align 屬性,因為某些移動端瀏覽器不支援Flex功能,影響到適配,而antd已經幫我做過了,只是需要我們採用以下寫法,否則無效 例如:

Good:

<Flex  direction="column" align="start" justify="startt">
複製程式碼

Bad:(這種寫法並沒有利用到Flex本身的適配)

<Flex style={{  
flexDirection: "column",  
backgroundColor: "white",
justifyContent: "flex-start"
}}>
複製程式碼

這樣的話,因為前端的相容性你需要寫很多適配的css程式碼,例如

{
      display: flex;
      display: -webkit-flex;
      flex-direction: row;
      -webkit-flex-direction: row;
      justify-content: flex-start;
      -webkit-justify-content: flex-start;
      align-items: center;
      -webkit-align-items: center;
}
複製程式碼

1.1.2 顯示指定flexDirection

因為某些情況下Flex無法使用,例如RN端的Touchable元件只能包裹原生元件,必須用View替代Flex,而View和Flex的預設方向是不一樣的,因此顯示寫出flexDirection,明確告知方向,方便遷移者改動程式碼

Good:

<Flex  direction="column">
     {...}
</Flex>
複製程式碼

Bad:(替換成View時候方向會錯)

<Flex>
     {...}
</Flex>
複製程式碼

1.2 ListView

在RN 0.51版本下,antd的ListView會報錯,還是使用RN提供的ListView,只需要修改import ListView即可,其他寫法完全一致

// 不推薦
import { ListView } from "antd-mobile";
// 推薦
import { ListView } from "react-native";
複製程式碼

2 程式碼規範

2.1 儘量元件化

某些頁面很複雜,常見的一種寫法是將頁面拆分成若干模組,每個模組寫一個moduleRender函式,再在render函式裡分別呼叫,類似以下

Bad:

class SomeComponent extends Component {
      renderSubOne() {
        return <Flex>{...}</Flex>;
      }
      renderSubTwo() {
        return <Flex>{...}</Flex>;
      }
      renderSubThree() {
        return <Flex>{...}</Flex>;
      }
      render() {
         return <Flex>
            {this.renderSubOne()}
            {this.renderSubTwo()}
            {this.renderSubThree()}
          </Flex>
      }
}
複製程式碼

Good:

  1. 因為遷移很可能是遷移某一部分,儘量拆分成元件遷移起來更靈活
  2. 這種寫法效能更高,分開寫的話每個元件有自己的生命週期,某個子元件重新整理時不會影響父元件
class SomeComponent extends Component {
      render() {
         return <Flex>
            <SubOne />
            <SubTwo />
            <SubThree />
          </Flex>
      }
}
複製程式碼

2.2 不要用css

關於樣式的寫法,RN和前端有個顯著的差別 RN:

import { StyleSheet } from "react-native";

const styles = StyleSheet.create({
 someContainer: {
    fontSize:16,
    fontWeight: 'bold',
  },
  ...
})

<Flex style={styles.container} />
複製程式碼

前端:

// js 檔案
import CSSModules from 'react-css-modules';
...

@CSSModules(styles)
...

<Flex className="someContainer">
複製程式碼
// css檔案
.someContainer{
      font-size: 16px;
      font-weight: bold;
 }
複製程式碼

由上面示例可知

  1. 前端的樣式是藏在css檔案內的,遷移起來需要一一去查詢
  2. 關鍵字命名不同(font-size,fontSize)

而這些不同都需要我們遷移的時候一一手動修改,工作量很大

推薦的寫法,是統一使用RN的寫法:

// 前端js檔案
const styles = { // 這裡不需要像RN一樣,使用StyleSheet.create
 someContainer: {
    fontSize:16,
    fontWeight: 'bold',
  },
  ...
}

<div style={styles.container} />
複製程式碼

2.3 第三方元件

挑選第三方元件要注意

  1. 儘量使用原生,或者antd
  2. 儘量選擇支援前端和移動端的
  3. 儘量選擇有人維護的
  4. 如果git無人維護或者年代久遠,建議將程式碼copy過來,而不是用npm管理,因為RN和React版本更新的原因,常常需要手動修改部分程式碼,才能執行,因此直接copy至工程裡,比較方便

3 差異

有一些差異是前端和RN天然的差異,需要注意

3.1 Image

載入圖片資源在兩端寫法並不一樣,需要手動修改

前端:

<img style={{ width: 98, height: 82 }} src={nullImg} alt="nullImg" />
複製程式碼

RN:

<Image style={{ height: 15, width: 15, marginLeft: 10 }} source={{ uri: 'search3' }} />
複製程式碼

3.1.1 RN的Image

需要特別注意一下的是,React Native 0.50.3以後,Image元件不再能包裹child

<Image> // 0.50.3以後,這種寫法報錯
      {...child...}
</Image>
複製程式碼

如果確實需要,只能用絕對位置了

3.2 Text文字

前端渲染文字有多種標籤,divspan等,但是RN端只有一種Text,這在遷移時會帶來很大的工作量,文字散落在各個地方,需要人工一一替換。 推薦使用react-intl,RN端是react-intl-native這個有Yahoo提供的第三方元件,實現了在前端、RN端的統一

Bad:

<div>文字</div>
<span>文字</span>
複製程式碼

Good:

  <FormattedMessage
    style={styles.valueDesc}
    id="someId"
    defaultMessage={text}
  />
複製程式碼

3.3 響應事件

前端:

// 可以新增在任何標籤上
<div onclick={()=>{}} />
<img onclick={()=>{}} />
複製程式碼

RN:

<TouchableHighlight onPress={}>// 只能有一個子元素,且必須是RN原生元件,不能是自定義元件
  <View> // 要用一個View來包裹更多的元素
      {child}
  </View
</TouchableHighlight>
複製程式碼

由上可知,點選事件遷移時,常常需要改動較多的程式碼

  1. 增加TouchableHighlight標籤
  2. 原標籤下,如果有多個子標籤,那麼還需要增加View來巢狀,還要注意樣式保持不變
  3. onClick改成onPress

3.4 路由跳轉

  • 前端使用react-route
  • RN端根據具體情況會有不同選擇,例如react-navigationreact-native-navigation

寫法上會有不同,需要遷移者根據具體選擇的庫,手動修改

3.5 PropTypes

PropTypes是React提供的一種型別檢測工具,但是隨著版本的變遷,從React 15.5起,PropTypes被移出了React,形成了一個單獨的庫,如果前端和RN兩邊版本不一致,還有可能需要人工大量修改

// react version < 15.5
import React, { Component, PropTypes } from 'react';

// react version >= 15.5
import React, { Component } from 'react';
import PropTypes from 'prop-types';
複製程式碼

3.6 全域性變數

前端js程式碼的執行環境通常是瀏覽器,瀏覽器本身提供全域性變數window,而RN端則沒有,因此不要在前端使用window全域性變數,而是要使用匯入檔案

Bad:

window.someVar = var
複製程式碼

Good:

// 新建constants.js檔案
const object = {
   website:'http://www.hao123.com',
   name:'好123',
};
export default object;

// 需要使用時匯入
import constants from './constansts.js'
<Text>{constants.name}</Text>
複製程式碼

相關文章