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:
- 因為遷移很可能是遷移某一部分,儘量拆分成元件遷移起來更靈活
- 這種寫法效能更高,分開寫的話每個元件有自己的生命週期,某個子元件重新整理時不會影響父元件
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;
}
複製程式碼
由上面示例可知
- 前端的樣式是藏在css檔案內的,遷移起來需要一一去查詢
- 關鍵字命名不同(font-size,fontSize)
而這些不同都需要我們遷移的時候一一手動修改,工作量很大
推薦的寫法,是統一使用RN的寫法:
// 前端js檔案
const styles = { // 這裡不需要像RN一樣,使用StyleSheet.create
someContainer: {
fontSize:16,
fontWeight: 'bold',
},
...
}
<div style={styles.container} />
複製程式碼
2.3 第三方元件
挑選第三方元件要注意
- 儘量使用原生,或者antd
- 儘量選擇支援前端和移動端的
- 儘量選擇有人維護的
- 如果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文字
前端渲染文字有多種標籤,div
,span
等,但是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>
複製程式碼
由上可知,點選事件遷移時,常常需要改動較多的程式碼
- 增加TouchableHighlight標籤
- 原標籤下,如果有多個子標籤,那麼還需要增加View來巢狀,還要注意樣式保持不變
- onClick改成onPress
3.4 路由跳轉
- 前端使用
react-route
- RN端根據具體情況會有不同選擇,例如
react-navigation
,react-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>
複製程式碼