【问题标题】:In react native this.setState() does not changes the state in fetch function在本机反应中 this.setState() 不会更改 fetch 函数中的状态
【发布时间】:2016-10-09 18:47:07
【问题描述】:

我整天都在寻找解决方案,我学到了很多东西,但没有弄清楚哪里出了问题。这是我的工作:

  1. 调用App构造函数;初始化状态加载、数据源和数据
  2. 当组件挂载时,程序使用请求的 URL 调用 getData 函数
  3. getData 函数是一个异步获取函数
  4. 然后将数据转换为 JSON
  5. 然后将 JSON 克隆为 webview 的数据块
  6. 然后调用 setState 函数,更改加载和数据。

这是 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。

【问题讨论】:

    标签: javascript json reactjs react-native


    【解决方案1】:

    我认为您误解了 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 是您存储数据源对象的位置。

    【讨论】:

      【解决方案2】:
       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}/>}
              />
      

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

      【讨论】:

      • 这不是唯一的问题。他也没有用他克隆的新数据源替换该州的数据源。请参阅下面的答案。
      猜你喜欢
      • 2020-05-08
      • 2022-11-17
      • 1970-01-01
      • 1970-01-01
      • 2018-10-19
      • 1970-01-01
      • 1970-01-01
      • 2018-04-09
      • 2021-10-06
      相关资源
      最近更新 更多