我在Android模拟器中运行以下代码,但我得到 null不是对象(评估'this.state.dataSource')错误。
拜托,你能帮我看看我做错了什么吗?由于某种原因,行dataSource={this.state.dataSource}
变为空。
import React, {
Component
} from 'react';
import {
AppRegistry,
ActivityIndicator,
ListView,
Text,
View,
StyleSheet
} from 'react-native';
import Row from './Row';
import Header from './Header';
import SectionHeader from './SectionHeader';
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: 20,
},
separator: {
flex: 1,
height: StyleSheet.hairlineWidth,
backgroundColor: '#8E8E8E',
},
});
export default class NoTocarList extends Component {
constructor(props) {
super(props);
const getSectionData = (dataBlob, sectionId) => dataBlob[sectionId];
const getRowData = (dataBlob, sectionId, rowId) =>
dataBlob[`${rowId}`];
fetch('http://xxxxx.mybluemix.net/get')
.then((response) => response.json())
.then((responseJson) => {
const ds = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2,
sectionHeaderHasChanged: (s1, s2) => s1 !== s2,
getSectionData,
getRowData
});
const {
dataBlob,
sectionIds,
rowIds
} =
this.formatData(responseJson);
this.state = {
dataSource: ds.cloneWithRowsAndSections(dataBlob, sectionIds,
rowIds)
}
})
}
formatData(data) {
const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
const dataBlob = {};
const sectionIds = [];
const rowIds = [];
for (let sectionId = 0; sectionId < alphabet.length; sectionId++) {
const currentChar = alphabet[sectionId];
const users = data.filter((user) =>
user.calle.toUpperCase().indexOf(currentChar) === 0);
if (users.length > 0) {
sectionIds.push(sectionId);
dataBlob[sectionId] = {
character: currentChar
};
rowIds.push([]);
for (let i = 0; i < users.length; i++) {
const rowId = `${sectionId}:${i}`;
rowIds[rowIds.length - 1].push(rowId);
dataBlob[rowId] = users[i];
}
}
}
return {
dataBlob,
sectionIds,
rowIds
};
}
render() {
return (
<View style={{flex: 1, paddingTop: 20}}>
<ListView
style={styles.container}
dataSource={this.state.dataSource}
renderRow={(rowData) => <Row {...rowData} />}
renderSeparator={(sectionId, rowId) => <View key={rowId} />}
style={styles.separator}
renderHeader={() => <Header />}
renderSectionHeader={(sectionData) => <SectionHeader {...sectionData} />}
/>
</View>
);
}
}
AppRegistry.registerComponent('NoTocar', () => NoTocarList);
答案 0 :(得分:1)
问题是您在渲染之后尝试异步更新状态,但期望第一次渲染的结果。另一个问题是你要覆盖状态而不是更新状态。
构造函数中的fetch
调用是异步的,这意味着构造函数已完成,并且在调用结算之前创建了组件(及其状态)。
constructor() {
fetch('http://xxxxx.mybluemix.net/get')
// ...
.then(() => {
// ...
// this code gets called after the component is created
// this state is also overwriting already created state
this.state = {
dataSource: ds.cloneWithRowsAndSections(dataBlob, sectionIds,
rowIds)
}
})
}
由于您的数据是异步获取的,因此您可以在加载时添加一个检查并显示进度指示器(您还应该使用setState
而不是覆盖状态):
constructor() {
this.state = {
dataSource: null // initialize it explicitly
}
fetch('http://xxxxx.mybluemix.net/get')
// ...
.then(() => {
// ...
// use set state
this.setState({
dataSource: ds.cloneWithRowsAndSections(dataBlob, sectionIds,
rowIds)
})
})
}
render(){
// on initial render, while the state hasn't been fetched yet
// show the spinner
if (!this.state.dataSource) {
return <ActivityIndicator />
}
return(
<View style={{flex: 1, paddingTop: 20}}>
...
</View>
);
}
答案 1 :(得分:1)
从您的示例中,您已将dataSource
作为null
传递给ListView
。所以你需要先使用
this.state({
dataSource: {}
})
收到Api
电话的回复后,您需要使用
dataSource state
this.setState({
dataSource: ds.cloneWithRowsAndSections(dataBlob, sectionIds,
rowIds)
})