#javascript #json #reactjs #react-native
#javascript #json #reactjs #react-native
Вопрос:
Я искал решения в течение дня, я многому научился, но не понял, что не так. Вот что я делаю:
- Вызов конструктора приложения; инициализация состояния загрузка, источник данных и данные
- когда компонент монтируется, программа вызывает функцию getData с запрошенным URL
- Функция getData является асинхронной функцией выборки
- затем данные преобразуются в JSON
- затем JSON клонируется, чтобы стать большим объектом данных для webview
- затем вызывается функция 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);
Я что-то пропустил? Спасибо за ваш ответ mighty Stack Overflow .
Ответ №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}/>}
/>
Источником данных должны быть данные, полученные из вашего вызова выборки. Поэтому источник данных должен быть установлен равным this.state.data .
Комментарии:
1. Это не единственная проблема afaik. Он также не заменяет источник данных в состоянии на новый, который он клонирует. Смотрите мой ответ ниже.