在React Native中的懒加载(lazyload)一直是个大问题,官方没有提供支持,而且React的结构也不利于实现这个功能
经过很长一段时间的挣扎与尝试之后终于完成了一款性能不错且使用较为简单的组件:react-native-lazyload
http://bbs.reactnative.cn/topic/407/react-native-lazyload
特性
- 纯javascript解决方案
- 只需要在原有代码的基础上进行一点点的改动就可以轻松实现界面、图片的懒加载
- 支持预加载距离设置
- 支持加载动画
- 支持长列表、长ScrollView未显示子元素的内存自动回收
- 健全的算法与缓存机制使得javascript线程性能飞快(不会因为滚动计算而造成js线程阻塞,1000个子元素的长列表,每次滚动js计算耗时控制在0~1ms之间)
安装
npm install react-native-lazyload
使用
- 引入
import {
LazyloadScrollView,
LazyloadListView,
LazyloadView,
LazyloadImage
} from 'react-native-lazyload';
- 替换
使用LazyloadScrollView
替换需要实现懒加载的ScrollView
,LazyloadListView
替换ListView
LazyloadView
替换需要被懒加载的View
,LazyloadImage
替换Image
LazyloadScrollView
,LazyloadListView
的用法与ScrollView
,ListView
完全一样
- 关联元素
给LazyloadScrollView
或LazyloadListView
添加 name 属性,并给LazyloadView
,LazyloadImage
添加与之对应的host属性
特别注意:
- 所有
LazyloadView
,LazyloadImage
需要在LazyloadScrollView
或LazyloadListView
内,并指定与之 name 属性相同的 host属性才能使懒加载生效,因为React不能实现元素的遍历,需要通过指定这两个属性建立懒元素与滚动元素之间的对应关系 - LazyloadView与LazyloadImage需要设定固定的宽高,否则它们被自动回收时会造成Scroll内容的闪动
一段简单的示意代码如下:
<LazyloadScrollView name="scroll">
<View>
<LazyloadView style={styles.view} host="scroll">
<Text>懒加载的内容</Text>
</LazyloadView>
</View>
...其他元素
<LazyloadImage style={styles.image} source={...图片地址} host="scroll" />
</LazyloadScrollView>
注意LazyloadScrollView的name属性与LazyloadView和LazyloadImage的host属性的对应关系
例子
下面这个例子可以在这里有完整的代码
import React, {
AppRegistry,
Component,
StyleSheet,
Text,
View,
ListView
} from 'react-native';
import {
LazyloadListView,
LazyloadView
} from 'react-native-lazyload';
import data from './MOCK_DATA.json';
class LazyloadListExample extends Component {
constructor() {
super(...arguments);
let ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.state = {
dataSource: ds.cloneWithRows(data)
};
}
renderRow = (file) => {
return <View
style={styles.view}
>
<LazyloadView
host="listExample"
style={styles.file}
>
<View style={styles.id}>
<Text style={styles.idText}>{file.id}</Text>
</View>
<View style={styles.detail}>
<Text style={styles.name}>{file.first_name} {file.last_name}</Text>
<Text><Text style={styles.title}>email: </Text><Text style={styles.email}>{file.email}</Text></Text>
<Text style={styles.ip}><Text style={styles.title}>last visit ip: </Text>{file.ip_address}</Text>
</View>
<View style={styles.gender}>
<Text style={[styles.genderText, file.gender === 'Male' ? styles.male : styles.female]}>{file.gender}</Text>
</View>
</LazyloadView>
</View>;
};
render() {
return (
<LazyloadListView
style={styles.container}
contentContainerStyle={styles.content}
name="listExample"
dataSource={this.state.dataSource}
renderRow={this.renderRow}
scrollRenderAheadDistance={200}
renderDistance={100}
pageSize={1}
initialListSize={10}
/>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF'
},
content: {
paddingTop: 20,
justifyContent: 'center',
alignItems: 'center'
},
view: {
height: 70,
width: 320,
paddingVertical: 5,
borderBottomWidth: StyleSheet.hairlineWidth,
borderBottomColor: '#666'
},
file: {
width: 320,
flex: 1,
flexDirection: 'row'
},
id: {
width: 50,
alignItems: 'center',
justifyContent: 'center'
},
idText: {
fontSize: 10
},
detail: {
justifyContent: 'space-around',
flex: 1
},
name: {
textAlign: 'center',
lineHeight: 15,
color: '#666',
marginBottom: 5
},
email: {
fontSize: 10,
color: 'blue',
textDecorationColor: 'blue',
textDecorationLine: 'underline',
textDecorationStyle: 'solid'
},
ip: {
fontSize: 12,
color: 'grey'
},
gender: {
width: 50,
alignItems: 'center',
justifyContent: 'center'
},
genderText: {
fontSize: 10
},
title: {
color: '#333',
fontSize: 12
},
male: {
color: 'skyblue'
},
female: {
color: 'pink'
}
});
export default LazyloadListExample;