您的位置:首页 > Web前端 > React

[教程]   ListView的使用和封装——实战React Native中级案例01

2017-05-29 05:51 639 查看

前言

在开发过程中最常见的任务就是建立一个列表,无论是联系人列表或是商品目录等等。为了提高开发效率,这里我们将对ListView进行整理和封装,使得其使用变得方便快捷。

为了检验组件的可用性,我们将开发下图的示例。该程序包含一个列表,可在程序初始化后现实一个数组中的数据。在点击
Add Item
按键后,列表将会添加新的项目。

这里要注意的是,ListView的部分应进行适当的封装,使得同样的组建可以快速的用于联系人列表或购物清单等场景。



想象驱动开发 (Wish-driven Development)

和测试驱动开发类似,想象驱动开发指的是先想象你的代码开发完成后应该如何使用,然后再进行开发,直到代码能够实现你描述的功能。

我想只需要写X我的代码就能做到Y => 一直修改代码直至实现你的愿望

在这个例子中我们希望ListView可以这样使用:

// 代码仅用于展示概念,放到程序里运行不了不要找我
<MyListView data={this.state.data} row={<Row />} />


为了实现代码的高重用性,我们希望列表中的每一行的外观都由组建
<Row />
决定,方便随时调整,然后作为一个
props
传到组件中,同时我们还不希望对于数据进行管理,而仅仅传入一个数组,ListView就可以自动将数据分发给每个
<Row />
组件。而数组发生变更的时候,
MyListView
也应该自动更新。

处理dataSource和数据刷新

ListView
的数据来自于dataSource,这个参数必须是一个
ListView.DataSource
对象。所以我们采用了这样的方法定义dataSource:

首先,定义一个
MyListView
类用来封装ListView:

class MyListView extends Component {
// Initialize the hardcoded data
constructor(props) {
super(props);
}
render() {
return (
<ListView
/>
);
}
}


然后,将
state
中的
dataSource
设置为一个
ListView.DataSource
类。

constructor(props) {
super(props);
this.state = {
dataSource: new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2})
};
}


在进行了上述设置后,我们就可以用
cloneWithRows
方法更新dataSource了。这里
cloneWithRows
的参数是一个数组,而返回值还是
ListView.DataSource
类。这个方法将方便React比较新的
dataSource
和原有的
dataSource
,并且仅在数据发生变动的时候才对页面进新更新。

updateData(data) {
this.setState({
dataSource: this.state.dataSource.cloneWithRows(data),
})
}


最后,我们还需要使用
updateData()
这个方法。
componentWillMount
负责在组件第一次完成初始化,并且接收到props但是还没有
render
前将state和props同步,而
componentWillReceiveProps
则负责在每次props变更后进行同步。

componentWillMount() {
this.updateData(this.props.data);
}
componentWillReceiveProps(nextProps) {
if(this.props.data !== nextProps.data){
this.updateData(nextProps.data);
}
}


创建子元件并传递props值

下一步我们要做的是使每一行的外观变成一个元件,并且可以从外部传递进去。在文档中,ListView的基本用法是这样的。

<ListView
dataSource={this.state.dataSource}
renderRow={(rowData) => <Text>{rowData}</Text>}
/>


即ListView会自动对于数据进行处理,并把每一行的数据作为
rowData
传递给一个React Component。这里,我们对于文档中的例子进行一些小的修改就能够达到目的:

<ListView
dataSource={this.state.dataSource}
renderRow={(rowData) => {
var newChild = React.cloneElement(
this.props.row,
{data:rowData}
);
return newChild
}}/>


这里,我们规定ListView应该有一个row参数,这个参数是一个组件,然后我们便用
React.cloneElement
方法对这个组件进行复制,并将
rowData
作为data参数传递给改组件。这样,这个组件就可通过下列方法使用
rowData
数据了:

class Row extends Component {
render() {
return(
<Text>{this.props.data}</Text>
)
}
}


代码展示

查看Demo:https://snack.expo.io/BkyPYRdZZ

import React, {Component} from 'react';
import { StyleSheet, Text, View, ListView, Button } from 'react-native';

class MyListView extends Component {
// Initialize the hardcoded data
constructor(props) {
super(props);
this.state = {
dataSource: new
4000
ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2})
};
}
updateData(data) { this.setState({ dataSource: this.state.dataSource.cloneWithRows(data), }) }
componentWillMount() { this.updateData(this.props.data); } componentWillReceiveProps(nextProps) { if(this.props.data !== nextProps.data){ this.updateData(nextProps.data); } }
render() {
return (
<ListView
dataSource={this.state.dataSource}
renderRow={(rowData) => {
var newChild = React.cloneElement(this.props.row, {data:rowData});
return newChild
}}
/>
);
}
}
class Row extends Component { render() { return( <Text>{this.props.data}</Text> ) } }
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: ['row 1', 'row 2', 'row 3', 'row 4'],
row: 5
};

}
addItem(){
this.setState(function(prevState) {
return {
data: [...prevState.data, ('row ' + prevState.row)],
row: prevState.row + 1
};
});
}
render() {
return (
<View style={styles.container}>
<MyListView data={this.state.data} row={<Row />} />
<Button title="Add Item" onPress={() => this.addItem()} />
</View>
);
}
}

const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
paddingTop: 22,
},
});


版权声明:本作品采用知识共享署名 3.0 未本地化版本许可协议进行许可,欢迎转载,请注明转载自Andrew Xie的学习笔记(http://blog.csdn.net/andrewxy)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息