React Native出現(xiàn)的目的本就是“l(fā)earn once, write anywhere”编整,F(xiàn)acebook希望人們能夠?qū)W習一次憎妙,到處使用壶唤,但是同樣是JS代碼稳诚,從前端移植到RN卓起,或者RN移植到前端和敬,卻并沒有想象的那么容易。事實上除了語法相同外戏阅,還有很多不一樣的地方昼弟,導致我們沒法做到直接copy,以下是我在做遷移代碼的時候奕筐,總結(jié)的一些經(jīng)驗
1 Antd Mobile
Antd Mobile的螞蟻金服開源的一套UI組件舱痘,已經(jīng)實現(xiàn)了前端、iOS离赫、Android的三端統(tǒng)一UI芭逝,推薦大家多多使用
1.1 Flex
1.1.1 使用Flex的參數(shù)
多用direction justify align 屬性,因為某些移動端瀏覽器不支持Flex功能渊胸,影響到適配旬盯,而antd已經(jīng)幫我做過了,只是需要我們采用以下寫法翎猛,否則無效
例如:
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 代碼規(guī)范
2.1 盡量組件化
某些頁面很復雜猛遍,常見的一種寫法是將頁面拆分成若干模塊,每個模塊寫一個moduleRender函數(shù),再在render函數(shù)里分別調(diào)用螃壤,類似以下
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
關(guān)于樣式的寫法,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文件內(nèi)的日麸,遷移起來需要一一去查找
- 關(guān)鍵字命名不同(font-size,fontSize)
而這些不同都需要我們遷移的時候一一手動修改寄啼,工作量很大
推薦的寫法,是統(tǒng)一使用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晰房,這個有Yahoo提供的第三方組件求摇,實現(xiàn)了在前端、RN端的統(tǒng)一
<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 路由跳轉(zhuǎn)
- 前端使用
react-route
- RN端根據(jù)具體情況會有不同選擇共屈,例如
react-navigation
绑谣,react-native-navigation
等
寫法上會有不同,需要遷移者根據(jù)具體選擇的庫拗引,手動修改
3.5 PropTypes
PropTypes是React提供的一種類型檢測工具借宵,但是隨著版本的變遷,從React v15.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代碼的運行環(huán)境通常是瀏覽器欲间,瀏覽器本身提供全局變量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>