環(huán)境安裝
參見官網(wǎng):
https://reactnative.dev/docs/environment-setup
https://reactnative.cn/docs/environment-setup
Notes:
針對依賴Node核心的包,RN沒有進(jìn)行處理,需要借助rn-nodeify處理,e.g. https://github.com/mvayngrib/react-native-crypto
針對Java依賴的版本問題,可以借助jetifier自動解決大部分的版本差異
-
針對Java依賴版本問題,可以通過patch-package打補(bǔ)丁
打出的補(bǔ)丁會包含很多無用的部分,可以選擇性刪除
-
打出的補(bǔ)丁可能二次修改,e.g.https://github.com/browserify/pbkdf2/blob/master/lib/default-encoding.js
- 源碼中
global.process && global.process.version,安裝后global.process && global."v16.13.0",patches/pbkdf2+3.1.2.patch需要二次修改
- 源碼中
項(xiàng)目創(chuàng)建
npx react-native@latest init rnProject
Notes:項(xiàng)目名稱只支持駝峰,不支持連字符。
項(xiàng)目運(yùn)行
npm run android
往模擬器或真機(jī)安裝APK:包運(yùn)行所需要的資源。
引用原生依賴,需要重新運(yùn)行該命令。
--mode=release臨時打包,輸出路徑android\app\build\outputs\apk\release
npm run start
運(yùn)行
Metro打包JS代碼,啟動熱更新,在模擬器或真機(jī)實(shí)時查看改動。--reset-cache清除Metro緩存,重新編譯JS代碼。
清除運(yùn)行緩存
-
"./gradlew" clean- 切換到
android目錄下,在命令行執(zhí)行該命令,可清除gradle緩存。
- 切換到
-
npx react-native start --reset-cache清除Metro緩存,重新編譯JS代碼
應(yīng)用場景:環(huán)境報(bào)錯、開發(fā)者工具出現(xiàn)問題
頁面適配
方案一:
// src/utils/px2dp.js
import { Dimensions, PixelRatio, StyleSheet } from 'react-native';
const windowWidth = Dimensions.get('window').width;
const px2dp = function (px) {
if (!isNaN(px)) {
return (windowWidth / 1080) * px / PixelRatio.get()
} else {
return 0
}
}
export default px2dp
// entry.js
import px2dp from '../utils/px2dp';
StyleSheet.create({
pageTitle: {
fontSize: px2dp(64),
lineHeight: px2dp(85),
paddingLeft: px2dp(100),
paddingRight: px2dp(100),
marginTop: px2dp(80),
},
})
方案二:
import React from 'react';
import {
StyleSheet,
Text,
Dimensions,
PixelRatio,
View,
} from 'react-native';
const { width: layoutWidth, height: layoutHeight } = Dimensions.get('window') // 獲取到設(shè)備pd
const ratio = PixelRatio.get() // 像素密度
const pixelWidth = PixelRatio.getPixelSizeForLayoutSize(layoutWidth) // pd轉(zhuǎn)px
const pixelHeight = PixelRatio.getPixelSizeForLayoutSize(layoutHeight) // pd轉(zhuǎn)px
const designWidth = 950 // 設(shè)計(jì)圖尺寸
/**
* 設(shè)備以px展示,以1/ratio縮放,通過translateX、translateY重置transform原點(diǎn)
* | 設(shè)計(jì)圖 | 設(shè)備 |
* | 20px | x |
* | 950px | pixelWidth |
* 同等占比:x = 20 * pixelWidth / 950
* ============================================
* 結(jié)合縮放比例:
* scale = pixelWidth / (designWidth * ratio)
* 其余組件可按設(shè)計(jì)圖設(shè)置像素即可
*/
const styles = StyleSheet.create({
adapter: {
width: pixelWidth,
height: pixelHeight,
transform: [
{
translateX: -pixelWidth * 0.5,
},
{
translateY: -pixelHeight * 0.5
},
{
scale: pixelWidth / (ratio * designWidth)
},
{
translateX: pixelWidth * 0.5,
},
{
translateY: pixelHeight * 0.5
}
]
},
fullscreen: {
width: designWidth,
height:90,
backgroundColor: 'red'
},
halfscreen: {
width: designWidth / 2,
height:90,
backgroundColor: 'green'
},
quaterscreen: {
width: designWidth / 4,
height:90,
backgroundColor: 'blue'
}
});
function App(): JSX.Element {
return (
<View style={styles.adapter}>
<View style={styles.fullscreen}>
<Text>1</Text>
</View>
<View style={styles.halfscreen}>
<Text>2</Text>
</View>
<View style={styles.quaterscreen}>
<Text>3</Text>
</View>
</View>
);
}
export default App;
結(jié)構(gòu)&樣式
原生組件:
-
只有特定的組件才有交互樣式與事件,如
Button、TouchableHighlight、TouchableOpacity,其余組件無法綁定onPress事件- 一般不選用
Button,而使用自定義Button組件,因?yàn)樵?code>Button樣式不好調(diào)節(jié)
- 一般不選用
不支持svg,需要借助第三方庫,e.g.
react-native-svg和react-native-svg-transformer結(jié)構(gòu)搭建:將HTML的標(biāo)簽用法完全忘記,重新根據(jù)文檔學(xué)習(xí)使用方法。
樣式:
只能使用組件規(guī)范的樣式,否則不起作用
lineHeight不能使文字居中,請使用justifyContent針對
Text組件,需要單獨(dú)定義相關(guān)樣式,不會繼承父級非Text組件Text樣式,e.g.不會從父級繼承color不支持漸變色、投影等效果,需要借助第三方庫,e.g.
react-native-linear-gradient、react-native-shadow-2
Notes:第三方庫的安裝,需要重新啟動項(xiàng)目,否則,會報(bào)模塊找不到。
嵌套ScrollView
flatlist嵌套在scrollView無法滾動,父子級都需要設(shè)置nestedScrollEnabled屬性-
scrollView必須設(shè)定一個高度,否則會使用默認(rèn)高度,并非由內(nèi)容撐開。注意
style與contentContainerStyle的區(qū)別scrollView高度設(shè)定:專設(shè)View組件包裹,scrollView高度設(shè)置為flex:1
代碼調(diào)試
react-native-debugger的使用
- 連接
react-native-debugger,需要應(yīng)用程序開啟Debug模式- 真機(jī):搖一搖手機(jī),出現(xiàn)操作面板,選擇
Debug
- 真機(jī):搖一搖手機(jī),出現(xiàn)操作面板,選擇

- 模擬器:模擬器聚焦后,使用
Ctrl + m打開操作面板- 雙擊
r是reload
- 雙擊
-
使用
react-native-debugger時,如果發(fā)出網(wǎng)絡(luò)請求,可能會在Network面板發(fā)現(xiàn)沒有request發(fā)起,請求(成功/失?。┗卣{(diào)沒有執(zhí)行。- 在
react-native-debugger非Chrome控制臺面板中右鍵,開啟Enable Network Inspect
- 在

使用
react-native-debugger時,如果發(fā)現(xiàn)Components面板始終空白,使用npx react-native start --reset-cache清除緩存啟動項(xiàng)目react-native-debugger的使用,需要同版本的react-devtools和react-devtools-core作為開發(fā)依賴。
當(dāng)前實(shí)例獲取
類同Chrome開發(fā)者工具,在RN任意調(diào)試工具的Console面板:
- 通過
$reactNative等同于import $reactNative from "react-native",可以使用react-native庫中的方法。

- 通過
$r可以獲取當(dāng)前選中節(jié)點(diǎn)實(shí)例

多種調(diào)試工具切換
在模擬器中開啟debug后,調(diào)試每次都會自動默認(rèn)打開debugger-ui頁面,如何關(guān)閉:
在啟動項(xiàng)目
npm run start的命令行中使用shift + d切換到模擬器并打開調(diào)試面板,此時點(diǎn)擊debug面板選項(xiàng)不再自動調(diào)起debugger-ui頁面。通過取消選中小勾號來解決它
Maintain Priority避免直接在模擬器中通過
Ctrl + M喚起面板,選擇debug,這樣會默認(rèn)調(diào)起debugger-ui
UI審查
開啟Android Studio:
- 通過右下角的
Layout Inspector,選擇模擬器或真機(jī)。

點(diǎn)擊結(jié)構(gòu),可以查看組件屬性
可以通過該面板的右上角設(shè)置,切換單位。

- 可以通過給組件賦值
testID、aria-label,進(jìn)行組件識別。
日志查看
開啟Android Studio:
通過下方的
logcat可以設(shè)備日志,可用于分析應(yīng)用程序崩潰原因。可進(jìn)行日志篩選,e.g.
package:com.awesomeproject level:error

外部字體
http://m.itdecent.cn/p/6000eb97d53b
- 不像H5一樣,針對不同的
font-weight設(shè)置@``font-face
@font-face { font-family: "Sans"; font-weight: 100; src: url("../assets/fonts/Thin.otf");}
@font-face { font-family: "Sans"; font-weight: 200; src: url("../assets/fonts/Light.otf");}
@font-face { font-family: "Sans"; font-weight: 400; src: url("../assets/fonts/Normal.otf");}
只能通過字體文件名設(shè)置不同的fontFamily:
// font-weight:100
f100: {
fontFamily: 'Thin' // 字體文件名
}
// font-weight:200
f200: {
fontFamily: 'Light' // 字體文件名
}
// font-weight:300
f300: {
fontFamily: 'Normal' // 字體文件名
}
動畫
toValue只能定義整型,如果動畫需要其他類型的值,需要使用interpolate無法對svg中的circle使用transform定義動畫,只能通過View或其他元素包裹,實(shí)現(xiàn)旋轉(zhuǎn)動畫
如果頁面內(nèi)有大量運(yùn)算,==
Animated會被阻塞,因?yàn)?code>Animated是在JS線程運(yùn)行,而非UI線程(https://stackoverflow.com/questions/56980044/how-to-prevent-setinterval-in-react-native-from-blocking-running-animation)
const animationRef = useRef({
strokeDashoffset: new Animated.Value(240),
rotateZ: new Animated.Value(1)
})
useEffect(() => {
const animationDef = () => {
Animated.loop(
Animated.sequence([
Animated.parallel([
Animated.timing(
animationRef.current.strokeDashoffset,
{
toValue: 240,
useNativeDriver: true,
duration: 900
}
),
Animated.timing(
animationRef.current.rotateZ,
{
toValue: 2,
useNativeDriver: true,
duration: 900
}
),
]),
Animated.parallel([
Animated.timing(
animationRef.current.strokeDashoffset,
{
toValue: 200,
useNativeDriver: true,
duration: 100
}
),
Animated.timing(
animationRef.current.rotateZ,
{
toValue: 3,
useNativeDriver: true,
duration: 100
}
),
]),
Animated.parallel([
Animated.timing(
animationRef.current.strokeDashoffset,
{
toValue: 200,
useNativeDriver: true,
duration: 900
}
),
Animated.timing(
animationRef.current.rotateZ,
{
toValue: 4,
useNativeDriver: true,
duration: 900
}
),
]),
Animated.parallel([
Animated.timing(
animationRef.current.strokeDashoffset,
{
toValue: 240,
useNativeDriver: true,
duration: 100
}
),
Animated.timing(
animationRef.current.rotateZ,
{
toValue: 5,
useNativeDriver: true,
duration: 100
}
),
])
])
).start()
}
animationDef()
}, [animationRef])
const rotateZ = animationRef.current.rotateZ.interpolate({
inputRange: [1, 2, 3, 4, 5],
outputRange: ['-100deg', '-424deg', '-500deg', '-784deg', '-820deg'],
})
常用第三方庫
項(xiàng)目需要重啟才可以,否則會報(bào)模塊找不到
-
漸變色
import LinearGradient from 'react-native-linear-gradient';
-
支持svg
"react-native-svg": "^13.9.0","react-native-svg-transformer": "^1.0.0",
全局樣式變量
"react-native-extended-stylesheet": "^0.12.0",
- 毛玻璃
@react-native-community/blur —— 只能有一個子節(jié)點(diǎn),多個子節(jié)點(diǎn)需要包裹
- 投影
yarn add react-native-shadow-2 —— 包裹唯一子節(jié)點(diǎn)不能使用margin,會導(dǎo)致Shadow不對齊,如果需要設(shè)置margin,使用View包裹Shadow元素
第三方庫使用帶來的問題
UseEffect vs. UseFocusEffect
使用react-native-navigation在同一路由棧中切換頁面,頁面沒有銷毀,所以,useEffect的清除回調(diào)不會被觸發(fā),需要考慮使用[useFocusEffect](https://reactnavigation.org/docs/bottom-tab-navigator)替代useEffect。
環(huán)境變量設(shè)置
使用react-native-dotenv或其他第三方庫設(shè)置環(huán)境變量,會出現(xiàn)報(bào)錯:Property left of AssignmentExpression expected node to be of a type ["LVal"] but instead got "StringLiteral" 。
需要修改rn-nodeify自動生成的shim.js文件,給process.env換一種賦值方式:
const isDev = typeof __DEV__ === 'boolean' && __DEV__
const env = process.env || {}
env['NODE_ENV'] = isDev ? 'development' : 'production'
process.env = env
if (typeof localStorage !== 'undefined') {
localStorage.debug = isDev ? '*' : ''
}
報(bào)錯:ReferenceError: Property 'TextEncoder' doesn't exist, js engine: hermes
https://github.com/hapijs/joi/issues/2141
android.support.annotation包不存在的錯誤
jetifier可一鍵解決
錯誤發(fā)生在你將你的Android應(yīng)用程序遷移到使用
androidx庫時import當(dāng)你使用androidx,你需要更新你的Android源代碼,用androidx.annotation包替換所有android.support.annotation包的語句。
https://www.qiniu.com/qfans/qnso-40380519【推薦】
react-native-webview Android postMessage 不工作
在安卓環(huán)境下,通過postmessage通信,需要使用document監(jiān)聽,ios下通過window監(jiān)聽。
https://github.com/react-native-webview/react-native-webview/issues/356
疑難雜癥
- 如何同時運(yùn)行模擬器和真機(jī)how to run react-native app on simulator and real device at the same time
https://stackoverflow.com/questions/51336123/how-can-i-run-two-react-native-applications
- 調(diào)試工具
flipper的React Devtools面板始終無法連接到應(yīng)用程序
進(jìn)行一下端口映射即可:adb reverse tcp:8097 tcp:8097