ReactNative null不是对象(评估'this.state.dataSource')

时间:2017-07-21 14:40:00

标签: javascript reactjs react-native react-native-android

我在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);

Error Message

2 个答案:

答案 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)
})