经过将近一个月的学习和开发,也做出了第一个由RN开发的 Android
应用。该文章旨在将近期学习的 React Native 所踩的坑、技术方案进行总结,为之后的开发留下可参考的财富,减少重复造轮子、踩坑的时间。(你所深陷的困境,可能别人早已轻而易举地解决,不要把脑力花在这上面!除非你想自己造轮子。)
要让 RN 跑起来,JDK 环境是必须的,网上已有非常多的 JDK 安装教程,找一篇跟着操作即可
这里要解决的问题是:假设我电脑上已原有 JDK8 版本,而官方文档要求如果 RN 版本 >= 0.67
,则需要 JDK11
的版本。那么此时我该如何 **同时配置两个JDK环境?**操作步骤如下:
JAVA8_HOME
和 JAVA11_HOME
JDK8
的环境,则在Path
里配置如下(JDK11同理),并点击确定Path
里将要使用的JDK版本放在最前面,即可完成切换java -version
验证当前版本是否已切换成功如下图,即代表当前环境为 JDK11
方式一:react-native-debugger
方式二:reactotron
【推荐】
Reactotron 官方链接:https://github.com/infinitered/reactotron/blob/master/docs/quick-start-react-native.md
其使用非常简单,根据官方文档进行操作即可,大体分为两个步骤:
有点击样式的 块元素
可以理解为:加了
hover
样式的div
。与之不同的是,在RN中,无法添加
onPress
来触发点击事件,因此需要在外层套一个
import { TouchableOpacity, Text } from 'react-native'
const handlePress = () => { ... }
const Index = () => {
<TouchableOpacity onPress={handlePress} activeOpacity={0.5}>
<View></View>
</TouchableOpacity>
}
常用属性:
activeOpacity
:控制手指按下时,元素的透明度变化值(类似css的 div:hover { opacity: 0.5 })UI给出的设计稿的屏幕宽度通常都是
375
,也就是以iPhone6
作为标准来设计,而实际开发中,为了适配各种机型的显示,我们需要声明如下函数,并在样式中使用它
// src/utils/stylesKits.js
import {Dimensions} from 'react-native';
// 手机中元素的宽度 = 手机屏幕 * 元素宽度 / 设计稿宽度(以375为例)
export const screenWidth = Dimensions.get('window').width;
export const screenHeight = Dimensions.get('window').height;
export const pxToDp = elePx => (screenWidth * elePx) / 375;
// xxx.js 组件中编写styles时引用
import {pxToDp} from '../../utils/stylesKits';
const styles = StyleSheet.create({
image: {
width: pxToDp(150),
height: pxToDp(150),
}
});
使用的路由和导航栏组件是
@react-navigation/native-stack
参考文档:https://reactnavigation.org/docs/native-stack-navigator
当希望实现类似「沉浸式导航栏」时,我们需要把顶部的导航栏隐藏,实现如下:
方法一:【不推荐,会占位】将导航栏的背景色和字体色调整成和页面背景色一致即可
{
headerStyle: {
backgroundColor: '#fff',
},
// 隐藏标头上的高程阴影 (Android) 或底部边框 (iOS)。
headerShadowVisible: false,
headerTintColor: '#fff',
}}
/>
方法二:【推荐】将 header
设置成 null
header
实际用途是:自定义标题栏,此时返回 null 相当于自定义了一个没有任何结构的导航栏,达到了隐藏原生导航栏的目的
{
header: () => {
return null
},
}}
/>
RN 无法像 CSS 一样,直接通过
linear-gradient
就可以设置渐变色需要引入第三方插件 https://www.npmjs.com/package/react-native-linear-gradient
yarn add react-native-linear-gradient
<LinearGradinet
start={{x: 0, y: 0}}
end={{x: 1, y: 0}}
colors={['#9b63cd', '#e0708c']}
style={{width: 200, height: 200}}
/>
当我尝试中 useEffect
中用如下代码写「异步函数」时,报错如下
useEffect must not return anything besides a function, which is used for clean-up.
// 错误写法
useEffect(async () => {
...
}, []);
正确写法如下
// 正确写法
useEffect(() => {
(async () => {
...
})();
}, []);
原生自带的
AsyncStorage
已被官方废弃,其推荐使用社区的包
因此,我们使用 @react-native-async-storage/async-storage
(社区的其他包也可以,该包较为容易上手),地址:https://react-native-async-storage.github.io/async-storage/docs/install。简单使用如下:
yarn add @react-native-async-storage/async-storage
import AsyncStorage from '@react-native-async-storage/async-storage';
① 写入的是如「字符串
」之类的值类型
const storeData = async (value) => {
try {
await AsyncStorage.setItem('@storage_Key', value)
} catch (e) {
// saving error
}
}
② 写入的是如「对象、数组
」之类的引用类型(需要先将对象转换成字符串)
const storeData = async (value) => {
try {
const jsonValue = JSON.stringify(value)
await AsyncStorage.setItem('@storage_Key', jsonValue)
} catch (e) {
// saving error
}
}
① 读取「字符串
」之类的值类型
const getData = async () => {
try {
const value = await AsyncStorage.getItem('@storage_Key')
if(value !== null) {
// value previously stored
}
} catch(e) {
// error reading value
}
}
② 读取「对象、数组
」之类的引用类型
const getData = async () => {
try {
const jsonValue = await AsyncStorage.getItem('@storage_Key')
return jsonValue != null ? JSON.parse(jsonValue) : null;
} catch(e) {
// error reading value
}
}