本文从一个Web开发者的角度简单梳理RN开发的基础知识,对比web开发可能让web同学更快的上手RN开发。
RN提供的框架组件都有style属性className, 使用styleSheet.create({})或style={{}},推荐前者性能更好fontWeight)TypeScript声明文件,编辑器会提醒你某个组件有哪些样式RN的组件样式是有规则的,先把高频样式用会,低频样式查查文档组件样式是有继承关系,分三层

flex布局 + transform + shadowView 组件样式 继承通用样式, 自身有 backgroundColor、border相关、opacityText、Image)都继承了View组件样式。因此View组件的私有样式其实也可以算作通用样式Text/Image组件的私有样式,就不能相互通用了。优点: 跨平台、高性能、易上手
Flex是跨平台的 Web/Android/IOS平台都在用, RN的布局引擎Yoga是Android/iOS通用的。
Flex布局代码,最终都会被Yoga引擎计算为精准的坐标系,然后渲染到屏幕上flexDirection默认值变为columnflex没有了auto none快捷值RN的样式远没有web强大,不过RN组件非常丰富,弥补了这方面的缺点。
display只有none和flexpostion相关
sticky 需要借助 <scrollview>的stickyHeaderIndices属性 来实现fixedImageBackgroundbackground、border、margintransfrom 写法有变化 transform: [{translateX:100}]text-indent推荐使用StyleSheet
ts// width: 750rpx = 100%
export const radio = (function(logicWidth: number) {
return logicWidth / 750
})(logicWidth);
<SafeAreaView>包裹页面,使用 <StatusBar>设置样式StatusBar.currentHeight, ios 设置默认值 20react-native-device-info因为RN的样式比较少,但是RN提供了大量的组件弥补这方面的缺陷
Image组件支持4种加载图片的方法
静态图片资源
静态图片资源的加载原理
网络图片
Android 用的是 Fresco 第三方图片加载组件的缓存机制iOS 用的是 NSURLCache 系统提供的缓存机制。它遵循的是 HTTP 的 Cache-Control 缓存策略Image.prefetch(url)宿主应用图片
html// Android drawable 文件目录
// iOS asset 文件目录
<Image source={{ uri: 'app_icon' }} />
// Android asset 文件目录
<Image source={{ uri: 'asset:/app_icon.png' }} />
Base64 图片

RN的点按组件经历了三代
Touchable组件Button组件Pressable组件第一代 Touchable 组件
TouchableWithoutFeedback:用于响应用户的点按操作,但不给出任何点按反馈效果。反馈效果由 4 个扩展类实现;TouchableNativeFeedback:给出当前原生平台的点按反馈效果,在 Android 中是涟漪(ripple)效果,就是从点击处散水波纹的效果TouchableOpacity:短暂地改变组件的透明度;TouchableHighlight:短暂地加深组件的背景色;TouchableBounce:有 bounce 回弹动画的响应效果。第二代 Button 组
Touchable 组件进行封装,别让开发者纠结选啥组件了TouchableNativeFeedback 组件,在 iOS 上是 TouchableOpacity 组件第三代 Pressable 组件
jsx
// 固定的基础样式
const baseStyle = { width: 50, height: 50, backgroundColor: 'red'}
<Pressable
onPress={handlePress}
style={baseStyle} >
<Text>按钮</Text>
</Pressable>
// 固定的基础样式
const baseStyle = { width: 50, height: 50, backgroundColor: 'red'}
<Pressable
onPress={handlePress}
style={({ pressed }) => [ /* 动态样式 */
baseStyle,
{ opacity: pressed ? 0.5 : 1}
]} >
<Text>按钮</Text>
</Pressable>
onPressIn: 开始响应事件,用户手指接触屏幕,且该手势被当前组件锁定后触发;onPressOut:结束响应事件,用户手指离开屏幕时触发。onPress: 在onPressOut中,如果距离onPressIn < 500ms则触发 onPressonLongPressref 的值不会因为组件刷新而重新声明,它是专门用来存储组件级别的信息的。
TextInput是输入框组件,相对于web,它的能力更强,可以定制键盘
一些与键盘优化相关的属性
enablesReturnKeyAutomatically iOS 独有的属性,默认是false 
returnKeyType 
textContentType android autoCompletekeyboardType可以控制键盘类型<Text>包裹;image网络图片必须给定宽高;
<ScrollView> 没有overflow:scroll
swiperef拿到原生组件,调用方法scrollTo(x, y, animated)FlatList / SectionList 后者支持分组,比如城市列表、联系人列表overflow:scroll 想要滚动就需要 <ScrollView>swiperef拿到原生组件,调用方法scrollTo(x, y, animated)<ScrollView> 会全部渲染元素,对于长列表就有性能问题<FlatList>和<SectionList>会渲染可视区及附近的元素,滚动时销毁远离可视区的元素并创建即将进入可视区的元素。<FlatList>做说明<FlatList> 的底层实现是 <VirtualizedList> 而<VirtualizedList> 的底层又是<ScrollView> 所以<FlatList> 可以使用<ScrollView>和<VirtualizedList>的大部分属性getItemLayout属性,如果不把列表项高度告知<FlatList>,<FlatList>会通过onLayout的布局回调动态计算,用户是会感觉到卡顿的官方的<FlatList>方案性能确实有的大幅提升,但性能还不够理想,社区提出了<ReyclerListView>方案, 它是改改在用(变更离开可视区的元素为即将进入可视区的元素)所以它的性能更好。
<ReyclerListView> 有一定学习成本,先来看一下使用
它有三个必填属性
dataProviderlayoutProviderrowRenderer示例
jsxfunction MyList() {
let dp = new DataProvider((r1, r2) => {
return r1 !== r2;
});
useEffect(() => {
fetch('XXX')
.then(res => res.json())
.then(arr => {
dp = dp.cloneWithRows(arr);
})
})
const _layoutProvider = new LayoutProvider(
index => {
if (index % 3 === 0) {
return ViewTypes.FULL;
} else {
return ViewTypes.HALF_RIGHT;
}
},
(type, dimension) => {
switch (type) {
case ViewTypes.HALF_RIGHT:
dimension.width = width / 2;
dimension.height = 160;
break;
case ViewTypes.FULL:
dimension.width = width;
dimension.height = 140;
break;
}
},
);
const _rowRenderer(type, data) {
//You can return any view here, CellContainer has no special significance
switch (type) {
case ViewTypes.HALF_RIGHT:
return (
<CellContainer style={styles.containerGridRight}>
<Text>Data: {data}</Text>
</CellContainer>
);
case ViewTypes.FULL:
return (
<CellContainer style={styles.container}>
<Text>Data: {data}</Text>
</CellContainer>
);
default:
return null;
}
}
return (
<RecyclerListView
onEndReached={fetchNextPage}
dataProvider={dp}
layoutProvider={layoutProvider}
rowRenderer={RowRenderer}
/>
)
}
分析
layoutProvider获取元素尺寸和类型,rowRenderer 根据类型渲染元素dataProvider 除了数据还要提供比对方面,提高性能

因为RecyclerListView 用的是 position:absolute 的绝对定位布局。所以要指定组件的宽高
如果宽高大致确定吗也是可以用的,可以开启forceNonDeterministicRendering 小幅修正布局位置
<RecyclerListView>貌似很完美,但不支持双列
解决方案1: 需要修改<RecyclerListView> 源码,如这个案例
解决方案2 就是使用<FlashList> 它是对<RecyclerListView>的二次封装
最后建议,如果有长列表瀑布流需求, 一开始就用<RecyclerListView>或<FlashList> , 不然随着业务迭代改造成本很大。
Platform.select({ios, android})Platform.OS执行不同逻辑web的e.target.value => RNe.nativeEvent.text
导航 react-navigation / react-native-navigation / 使用原生导航管理RN视图
动画 使用Animated
ScrollView实现Web端Swipe组件的脚标动画 Animated.eventref获取到原生组件 调用 setNativeProps 方法measure measureLayout)+ 监听滚动 可实现类似Web端的IntersectionObserver的功能
measure方法layout 方法在渲染前可以拿到文本元素尺寸(web需要渲染后才知道)JS 包含浏览器API、BOM 和 ECMA规范两部份组成 由JS引擎(chrome V8 / safari JSCore )提供。RN >=7.0使用 Hermes引擎 <7.0使用 JSCoreXMLHttpRequest / fetch / WebSocket 没有跨域问题Babel 做了语法转换 内置了API和Polyfillsrequire / consolesetTimeout、setInterval、requestAnimationFrame、setImmediate__DEV__本文作者:郭敬文
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!