最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - ReactNative null is not an object (evaluating 'this.state.dataSource') - Stack Overflow

programmeradmin2浏览0评论

I am running the following code in Android emulator but I am getting null is not an object (evaluating 'this.state.dataSource') error. Please, could you help me to see what I am doing wrong? For some reason the line dataSource={this.state.dataSource} is getting null.

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('')
      .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);

I am running the following code in Android emulator but I am getting null is not an object (evaluating 'this.state.dataSource') error. Please, could you help me to see what I am doing wrong? For some reason the line dataSource={this.state.dataSource} is getting null.

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/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);

Share Improve this question edited Jul 21, 2017 at 14:58 nem035 35.5k6 gold badges92 silver badges104 bronze badges asked Jul 21, 2017 at 14:39 Daniel CabreraDaniel Cabrera 431 gold badge1 silver badge7 bronze badges 1
  • don't return to state null value use empty str "" – Omar bakhsh Commented Jan 26, 2021 at 3:34
Add a ment  | 

2 Answers 2

Reset to default 2

From your example you have passed the dataSource as null to the ListView. So you need to initialize it first by using

this.state({
  dataSource: {}
})

After getting the response from the Api call you need to set the dataSource state by using

this.setState({
  dataSource: ds.cloneWithRowsAndSections(dataBlob, sectionIds, 
                  rowIds)
})

The issue is that you're trying to update the state asynchronously, after a render, but are expecting the result on the first render. Another issue is that you're overwriting the state instead of updating it.

The fetch call in your constructor is async, meaning the constructor is finished and the ponent (along with its state) is created before that call resolves.

constructor() {

  fetch('http://xxxxx.mybluemix/get')
  // ...
  .then(() => {
  // ...

    // this code gets called after the ponent is created
    // this state is also overwriting already created state
    this.state = {
      dataSource: ds.cloneWithRowsAndSections(dataBlob, sectionIds, 
                  rowIds)
    }
  })
}

Since your data is obtained asynchronously, you can add a check and show a progress indicator while its loading (you should also use setState instead of overwriting the state):

constructor() {

  this.state = {
    dataSource: null // initialize it explicitly
  }

  fetch('http://xxxxx.mybluemix/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>
  );
}
发布评论

评论列表(0)

  1. 暂无评论