Matthew Sheets
Matthew Sheets

Reputation: 67

React-Native Nested Array

I am trying to reach a nested array 4 objects deep, I have based my code off the example here: http://facebook.github.io/react-native/docs/tutorial.html#content

The error I get is:

undefined is not an object (evaluating 'Object.keys(dataBlob[sectionID])')

ListViewDataSource.js @ 206:0

cloneWithRowsAndSections ListViewDataSource.js @205:0

cloneWithRows ListViewDataSource.js @166:0

index.ios.js @ 40:0

This is a example of the json I have:

{
    "json": {
        "data": {
            "updated": {
                "$t": "04 Nov 2015 2321 GMT"
            },
            "flux": {
                "$t": "111"
            },
            "aindex": {
                "$t": "41"
            },
            "kindex": {
                "$t": "3"
            },
            "kindexnt": {
                "$t": "No Report"
            },
            "xray": {
                "$t": "B6.0"
            },
            "sunspots": {
                "$t": "95"
            },
            "heliumline": {
                "$t": "131.8"
            },
            "protonflux": {
                "$t": "3.14e-01"
            },
            "electonflux": {
                "$t": "5.46e+02"
            },
            "aurora": {
                "$t": "1"
            },
            "normalization": {
                "$t": "1.99"
            },
            "latdegree": {
                "$t": "67.5"
            },
            "solarwind": {
                "$t": "564.3"
            },
            "magneticfield": {
                "$t": "0.2"
            },
            "calculatedconditions": {
                "band": [
                    {
                        "name": "80m-40m",
                        "time": "day",
                        "$t": "Poor"
                    },
                    {
                        "name": "30m-20m",
                        "time": "day",
                        "$t": "Good"
                    },
                    {
                        "name": "17m-15m",
                        "time": "day",
                        "$t": "Fair"
                    },
                    {
                        "name": "12m-10m",
                        "time": "day",
                        "$t": "Poor"
                    },
                    {
                        "name": "80m-40m",
                        "time": "night",
                        "$t": "Fair"
                    },
                    {
                        "name": "30m-20m",
                        "time": "night",
                        "$t": "Good"
                    },
                    {
                        "name": "17m-15m",
                        "time": "night",
                        "$t": "Fair"
                    },
                    {
                        "name": "12m-10m",
                        "time": "night",
                        "$t": "Poor"
                    }
                ]
            }
        }
    }
}

Using the example I have the following in my index.ios.js:

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 */
'use strict';

var React = require('react-native');
var {
  AppRegistry,
  Image,
  ListView,
  StyleSheet,
  Text,
  View,
} = React;


var API_URL = 'http://url.com/file.json';
var REQUEST_URL = API_URL;

var HFStatus = React.createClass({
  getInitialState: function() {
    return {
      dataSource: new ListView.DataSource({
        rowHasChanged: (row1, row2) => row1 !== row2,
      }),
      loaded: false,
    };
  },

  componentDidMount: function() {
    this.fetchData();
  },

  fetchData: function() {
    fetch(REQUEST_URL)
      .then((response) => response.json())
      .then((responseData) => {
        this.setState({
          dataSource: this.state.dataSource.cloneWithRows(responseData.datas),
          loaded: true,
        });
      })
      .done();
  },

  render: function() {
    if (!this.state.loaded) {
      return this.renderLoadingView();
    }

    return (
      <ListView
        dataSource={this.state.dataSource}
        renderRow={this.renderdata}
        style={styles.listView}
      />
    );
  },

  renderLoadingView: function() {
    return (
      <View style={styles.container}>
        <Text>
          Loading datas...
        </Text>
      </View>
    );
  },

  renderdata: function(data) {
    return (
      <View style={styles.container}>
          <Text style={styles.title}>{data.json.data.calculatedconditions.band.name}</Text>
          <Text style={styles.title}>{data.json.data.calculatedconditions.band.time}</Text>
          <Text style={styles.title}>{data.json.data.calculatedconditions.band.$t}</Text>
      </View>
    );
  },
});

var styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: 'row',
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  rightContainer: {
    flex: 1,
  },
  title: {
    fontSize: 20,
    marginBottom: 8,
    textAlign: 'center',
  },
  year: {
    textAlign: 'center',
  },
  thumbnail: {
    width: 53,
    height: 81,
  },
  listView: {
    paddingTop: 20,
    backgroundColor: '#F5FCFF',
  },
});


AppRegistry.registerComponent('HFStatus', () => HFStatus);

Upvotes: 2

Views: 3747

Answers (2)

Nader Dabit
Nader Dabit

Reputation: 53711

It looks like you're trying to run clonewithrows on an object instead of an array. What you should do is this: (here is a working example with your data)

fetchData: function() {

  fetch(REQUEST_URL)
      .then((response) => response.json())
      .then((responseData) => {
        this.setState({
          dataSource: this.state.dataSource.cloneWithRows(responseData.json.data.calculatedconditions.band),
          loaded: true,
        });
      })
      .done();
  }

Then, in the renderdata function:

renderdata: function(data) {
    return (
      <View style={styles.container}>
          <Text style={styles.title}>{data.name}</Text>
          <Text style={styles.title}>{data.time}</Text>
          <Text style={styles.title}>{data.$t}</Text>
      </View>
    );
  },

https://rnplay.org/apps/D2soaw

Upvotes: 5

jevakallio
jevakallio

Reputation: 35970

The ListView.DataSource.cloneWithRows method expects an array of data, and you appear to be passing it an object. Your sample data doesn't give away the exact format of your response, but by converting the API response into an array of items should solve the problem.

The confusing error message is caused by the fact that ListView.DataSource has another method, cloneWithRowsAndSections, that allows you to split your list view into sections with sticky section headers. This method in turn expects an object, where each key represents a section ID, and value is an array containing the row items belonging to that section.

It appears that when passing an object to cloneWithRows, React Native defaults to the cloneWithRowsAndSections behaviour, but because the object is not in a valid format, the rendering fails.

Upvotes: 1

Related Questions