官方教程逐步介绍如何使用 ListView 来显示 JSON 数据。我们从模拟数据开始上手 React Native。在 JS 文件顶部声明常量,例如定义模拟电影数据。
var MOCKED_MOVIES_DATA = [ {title: 'Title', year: '2015', posters: {thumbnail: 'http://i.imgur.com/UePbdph.jpg'}}, ];
首先渲染一部电影的标题、年份和缩略图。由于缩略图是 Image 组件,需要在导入列表中添加 Image。
import React, {
Component,
} from 'react';
import {
AppRegistry,
Image,
StyleSheet,
Text,
View,
} from 'react-native';
修改 render 方法来渲染模拟数据。
render() {
var movie = MOCKED_MOVIES_DATA[0];
return (
<View style={styles.container}>
<Text>{movie.title}</Text>
<Text>{movie.year}</Text>
<Image source={{uri: movie.posters.thumbnail}} />
</View>
);
}
重新加载 JS 后,您会看到标题和年份,但 Image 可能未渲染,因为缺少宽高样式。通过 StyleSheet 定义样式并应用到 Image 组件。
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
thumbnail: {
width: 53,
height: 81,
},
});
将样式应用到 Image 后,重新加载 JS 将显示完整视图。
接下来改进布局,在图片右侧放置文字,使标题更大并居中。添加一个容器用于水平布局。
return (
<View style={styles.container}>
<Image
source={{uri: movie.posters.thumbnail}}
style={styles.thumbnail}
/>
<View style={styles.rightContainer}>
<Text style={styles.title}>{movie.title}</Text>
<Text style={styles.year}>{movie.year}</Text>
</View>
</View>
);
更新样式以使用 FlexBox 布局,设置 flexDirection 为 'row' 实现水平排列。
container: {
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
为 rightContainer 添加样式,使其占据剩余空间。
rightContainer: {
flex: 1,
},
设置文字样式以增强视觉效果。
title: {
fontSize: 20,
marginBottom: 8,
textAlign: 'center',
},
year: {
textAlign: 'center',
},
重新加载 JS 后,视图将呈现更美观的布局。
现在转向获取真实数据。使用 Rotten Tomatoes 的 API 示例数据,定义请求 URL。
var REQUEST_URL = 'https://raw.githubusercontent.com/facebook/react-native/master/docs/MoviesExample.json';
在组件中初始化状态,用于跟踪电影数据是否加载。
constructor(props) {
super(props);
this.state = {
movies: null,
};
}
组件加载完成后发送请求,通过 componentDidMount 调用 fetchData 方法。
componentDidMount() { this.fetchData(); }
fetchData 方法使用 fetch 获取数据,并在解析后更新状态。
fetchData() {
fetch(REQUEST_URL)
.then((response) => response.json())
.then((responseData) => {
this.setState({
movies: responseData.movies,
});
})
.done();
}
修改 render 方法,根据加载状态显示加载视图或电影数据。
render() {
if (!this.state.movies) {
return this.renderLoadingView();
}
var movie = this.state.movies[0];
return this.renderMovie(movie);
}
renderLoadingView() {
return (
<View style={styles.container}>
<Text>
Loading movies...
</Text>
</View>
);
}
renderMovie(movie) {
return (
<View style={styles.container}>
<Image
source={{uri: movie.posters.thumbnail}}
style={styles.thumbnail}
/>
<View style={styles.rightContainer}>
<Text style={styles.title}>{movie.title}</Text>
<Text style={styles.year}>{movie.year}</Text>
</View>
</View>
);
}
重新加载 JS 后,将显示“Loading movies...”直到数据返回,然后渲染第一条电影。
为了高效渲染所有电影数据,引入 ListView 组件。更新导入列表。
import React, {
Component,
} from 'react';
import {
AppRegistry,
Image,
ListView,
StyleSheet,
Text,
View,
} from 'react-native';
修改 render 方法,使用 ListView 渲染数据源。
render() {
if (!this.state.loaded) {
return this.renderLoadingView();
}
return (
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderMovie}
style={styles.listView}
/>
);
}
在构造函数中初始化 dataSource 和 loaded 状态。
constructor(props) {
super(props);
this.state = {
dataSource: new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2,
}),
loaded: false,
};
}
更新 fetchData 方法以设置 dataSource。
fetchData() {
fetch(REQUEST_URL)
.then((response) => response.json())
.then((responseData) => {
this.setState({
dataSource: this.state.dataSource.cloneWithRows(responseData.movies),
loaded: true,
});
})
.done();
}
为 ListView 添加样式。
listView: {
paddingTop: 20,
backgroundColor: '#F5FCFF',
},
最终代码整合了所有步骤,实现了从模拟数据到真实 API 的 ListView 渲染。
/**
* Sample React Native App
* https://github.com/facebook/react-native
*/
import React, {
Component,
} from 'react';
import {
AppRegistry,
Image,
ListView,
StyleSheet,
Text,
View,
} from 'react-native';
var REQUEST_URL = 'https://raw.githubusercontent.com/facebook/react-native/master/docs/MoviesExample.json';
class AwesomeProject extends Component {
constructor(props) {
super(props);
this.state = {
dataSource: new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2,
}),
loaded: false,
};
}
componentDidMount() {
this.fetchData();
}
fetchData() {
fetch(REQUEST_URL)
.then((response) => response.json())
.then((responseData) => {
this.setState({
dataSource: this.state.dataSource.cloneWithRows(responseData.movies),
loaded: true,
});
})
.done();
}
render() {
if (!this.state.loaded) {
return this.renderLoadingView();
}
return (
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderMovie}
style={styles.listView}
/>
);
}
renderLoadingView() {
return (
<View style={styles.container}>
<Text>
Loading movies...
</Text>
</View>
);
}
renderMovie(movie) {
return (
<View style={styles.container}>
<Image
source={{uri: movie.posters.thumbnail}}
style={styles.thumbnail}
/>
<View style={styles.rightContainer}>
<Text style={styles.title}>{movie.title}</Text>
<Text style={styles.year}>{movie.year}</Text>
</View>
</View>
);
}
}
var styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
rightContainer: {
flex: 1,
},
title: {
fontSize: 20,
marginBottom: 8,
textAlign: 'center',
},
year: {
textAlign: 'center',
},
thumbnail: {
width: 53,
height: 81,
},
listView: {
paddingTop: 20,
backgroundColor: '#F5FCFF',
},
});
AppRegistry.registerComponent('AwesomeProject', () => AwesomeProject);
本教程详细介绍了 React Native 中 ListView 的使用,从基础渲染到数据获取,帮助您构建高效列表视图。