在本机中,this.setState()不会更改fetch函数中的状态

时间:2016-10-09 18:47:07

标签: javascript json reactjs react-native

我一直在寻找解决方案,我学到了很多,但没弄清楚出了什么问题。我在这做什么:

  1. 调用App构造函数;初始化状态加载,dataSource和数据
  2. 当组件安装时,程序使用请求的URL调用getData函数
  3. getData函数是异步提取函数
  4. 然后数据转换为JSON
  5. 然后克隆JSON成为webview的数据包
  6. 然后调用setState函数,改变加载和数据。
  7. 这是setState不会触发的地方。甚至不是渲染(它应该)。每个教程,每个论坛都以这种方式显示它(也是合乎逻辑的)。

    以下是代码:

    import Exponent from 'exponent';
    import React from 'react';
    import {
      StyleSheet,
      Text,
      View,
      ListView,
      ActivityIndicator
    } from 'react-native';
    
    import { Button, Card } from 'react-native-material-design';
    import {UnitMenuCard} from './unitmenucard.js';
    
    class App extends React.Component {
      constructor(props) {
        super(props);
        const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
        this.state = {
          loading: true,
          dataSource: ds,
          data: null
        }
      }
    
      componentDidMount() {
        //console.log('componentDidMount');
        this.getData('https://dl.dropboxusercontent.com/u/76599014/testDATA.json');
      }
    
      getData(url) {
        console.log('loading data');
        return fetch(url).then(
          (rawData) => {
            console.log('parsing data');
            //console.table(rawData);
            return rawData.json();
          }
        ).then(
          (jsonData) =>
          {
            console.log('parsing to datablobs');
            let datablobs = this.state.dataSource.cloneWithRows(jsonData);
            console.log('datablobs: ' + datablobs);
            return datablobs;
          }
        ).then(
            (datablobs) => {
              console.log('setting state');
              this.setState = ({
                loading: false,
                data: datablobs
              });
              console.log('the loading is '  + this.state.loading);
              console.log('the data is '  + this.state.data);
            }
        ).catch((errormsg) =>
          {console.error('Loading error: ' + errormsg);}
        );
      }
    
      render() {
        console.log('loading is ' + this.state.loading);
        var dataToDisplay = '';
        if(this.state.loading) {
          dataToDisplay = <ActivityIndicator animated={true} size='large' />
        } else {
          //let jdt = this.state.dataSource.cloneWithRows(this.state.data);
          dataToDisplay = <ListView
            dataSource={this.state.ds}
            renderRow={(unit) => <UnitMenuCard name={unit.name} image={unit.picture} menu={unit.menu}/>}
            />
        }
        return (
          <View style={styles.container}>
            {dataToDisplay}
          </View>
        );
      }
    }
    
    const styles = StyleSheet.create({
      container: {
        flex: 1,
        backgroundColor: '#fff',
    
      },
    });
    
    Exponent.registerRootComponent(App);
    

    我错过了什么吗?谢谢你的回答强大Stack Overflow。

2 个答案:

答案 0 :(得分:0)

我认为您误解了DatSource的工作原理。

getInitialState: function() {
  var ds = new ListViewDataSource({rowHasChanged: this._rowHasChanged});
  return {ds};
},
_onDataArrived(newData) {
  this._data = this._data.concat(newData);
   this.setState({
     ds: this.state.ds.cloneWithRows(this._data)
   });
}

这取自此处的文档:https://facebook.github.io/react-native/docs/listviewdatasource.html

了解如何在状态中克隆数据源对象。关键是你调用cloneWithRows传递从API返回的数据(在你的情况下是jsonData)。这将创建一个克隆的数据源,其中包含刚刚提取的数据。

在您的代码中,您只需创建数据源的克隆,但永远不会替换列表视图链接到的实际链接。你应该这样做:

.then(
    (datablobs) => {
      console.log('setting state');
      this.setState = ({
        loading: false,
        dataSource: datablobs
      });
      console.log('the loading is '  + this.state.loading);
      console.log('the data is '  + this.state.data);
    }

您不需要state.data,列表视图从数据源对象读取。您也可以通过简单地将所有内容整合在一起来避免两次.then次呼叫。

您还有另一个问题。您将列表视图链接到状态中的错误属性。列表中的视图代码应该是:

dataToDisplay = <ListView
    dataSource={this.state.dataSource}
    renderRow={(unit) => <UnitMenuCard name={unit.name} image={unit.picture}   menu={unit.menu}/>}
    />

this.state.dataSource是存储数据源对象的地方。

答案 1 :(得分:0)

 dataToDisplay = <ListView
        dataSource={this.state.ds}  // <- you set the dataSource to this.state.ds instead of this.state.data
        renderRow={(unit) => <UnitMenuCard name={unit.name} image={unit.picture} menu={unit.menu}/>}
        />

数据源应该是您从提取调用中获得的数据。因此,dataSource应设置为等于this.state.data。