0

"objects are not valid as a react child (found: object with keys {date, events}). If you meant to render a collection of children, use an array instead or wrap the object using createFragment(object) from the React add-ons. Check the render method of View."

So I have kind of a cascade of method calls. I'm retrieving dates with events inside of those. It feels like I'm doing this correctly, but am getting the above error. I've tried setting createFragment on places, but still getting the error. Here's the code:

  import React, { Component } from 'react';
  import {
    AppRegistry,
    Text,
    View,
    ScrollView,
    RefreshControl,
    StyleSheet,
    Dimensions,
    TextInput,
    Linking,
    TouchableNativeFeedback
   } from 'react-native';

  var _ = require('lodash');
  var {width, height} = Dimensions.get('window');
  var renderif = require('render-if');
  var createFragment = require('react-addons-create-fragment');

  var IMAGES_PER_ROW = 1

  class FunInATL extends Component {
    constructor(props) {
      super(props);
      this.state = {
        currentScreenWidth: width,
        currentScreenHeight: height,
        dates: [],
        boxIndex: 0,
        showBox: false,
        refreshing: false
      };
    }

        handleRotation(event) {
          if (!this.state) {
            return;
          }

          var layout = event.nativeEvent.layout
          this.state({currentScreenWidth: layout.width, currentScreenHeight: layout.height })
        }

        calculatedSize() {
          var size = this.state.currentScreenWidth / IMAGES_PER_ROW
          return {width: size}
        }

        renderRow(events) {
          return events.map((events, i) => {
            return (
              <Image key={i} style={[this.getImageStyles(), styles.image, this.calculatedSize() ]} source={{uri: event.image}} />
            )
          })
        }

        openUrl(url) {
          Linking.canOpenURL(url).then(supported => {
              if (supported) {
                Linking.openURL(url);
              } else {
                console.log('nope :: ' + url);
              }
          }).catch(err => console.error('An error occurred', err));
        }

        getImageStyles(featured, category) {
            let options = {
              borderColor: 'gold',
              borderWidth: featured ? 1 : 0
            }

            if (!category) {
                options.height = featured ? 250 : 125
            }

            return options;
        }

        _clickImage(event, index) {
          if (event.title) {
            let new_val = !this.state.showBox
            this.setState({
                dates: this.state.dates,
                showBox: new_val,
                boxIndex: new_val ? index : 0
            });
          }

        }

        componentDidMount() {
          this.state = {
              dates: [],
              boxIndex: 0,
              showBox: false,
              refreshing: false
          };
          this.getApiData();

          Linking.addEventListener('url', this.handleUrl);
        }

        componentWillUnmount() {
            Linking.removeEventListener('url', this.handleUrl);
        }

        getApiData() {
          var _this = this;
          return fetch('https://www.funinatl.com/mobile2.php?v1')
            .then(function(response) {
              return response.json()
            })
            .then((responseJson) => {
              var dates = createFragment(responseJson.events)
              return;

              let _this = this;

              date.events.map((event, i) => (
                date.events[i] = event
              ))

              var datesData = [];
              dates.map((date, i) => (
                datesData.push({
                  date: i,
                  events: createFragment(date.events)
                })
              ))

              _this.setState({
                dates: createFragment(datesData),
                boxIndex: 0,
                showBox: false
              })

              console.error(this.state);
            })
            .catch((error) => {
              console.error(error);
            })
            .done();
        }

        renderDates() {
          return this.state.dates.map((date) =>
                (
                  <View>
                    <Text style={styles.dateHeader}>{ date.date }</Text>

                    <View>
                    {this.renderEvents(date.events)}
                    </View>
                  </View>

            ))
        }

        renderImage(event, index) {
            if (this.state.showBox && this.state.boxIndex == index) {
              return (
                <View>
                  <TouchableNativeFeedback onPress={()=>this._clickImage(event, index)}>
                      <Image source={{ uri: event.image }} style={[styles.image, this.calculatedSize(), this.getImageStyles(event.featured), { height: 100 }]} />
                  </TouchableNativeFeedback>
                  <View style={{ flexDirection:'row', padding: 15 }}>
                      <Text style={styles.price}>{event.price}</Text>
                      <Text style={styles.time}>{event.time}</Text>
                      <TouchableNativeFeedback onPress={()=>this.openUrl(event.website)}>
                          <Text style={styles.btn}>Website</Text>
                      </TouchableNativeFeedback>
                  </View>

                      {renderif(event.venue)(
                          <TouchableNativeFeedback onPress={()=>this.openUrl(event.venue)}>
                              <Text style={styles.btn}>Venue</Text>
                          </TouchableNativeFeedback>
                      )}

                </View>
              )
            } else {
              return (
                <View>
                    <TouchableNativeFeedback onPress={()=>this._clickImage(event, index)}>
                        <Image source={{ uri: event.image }} style={[styles.image, this.calculatedSize(), this.getImageStyles(event.featured)]} />
                    </TouchableNativeFeedback>
                </View>
              )
            }
        }

        renderEvents(events) {
          return events.map((event, i) =>
            (
              <View>
                <Text style={[styles.eventCategory, this.getImageStyles(event.featured, true)]}>{event.category}</Text>
                <View>
                  {this.renderImage(event, i)}
                </View>
                <Text style={[styles.eventTitle, this.getImageStyles(event.featured, true)]}>{event.title}</Text>
              </View>
          ));
        }

        _onRefresh() {
          this.setState({refreshing: true});
          fetchData().then(() => {
            this.setState({refreshing: false});
          });
        }

        render() {
          return (
            <ScrollView onLayout={this.handleRotation} contentContainerStyle={styles.scrollView} refreshControl={
                <RefreshControl
                  refreshing={this.state.refreshing}
                  onRefresh={this._onRefresh.bind(this)}
                  tintColor="#ff0000"
                  title="Loading..."
                  titleColor="#00ff00"
                  colors={['#ff0000', '#00ff00', '#0000ff']}
                  progressBackgroundColor="#ffff00"
                />
              }>
              <Text style={styles.header}>FunInATL</Text>
                  {this.renderDates()}
            </ScrollView>
          )
        }
      }

  var styles = StyleSheet.create({

    row: {
      flexDirection: 'row',
      alignItems: 'center',
      justifyContent: 'flex-start',
      textAlign: 'center',
      padding: 10
    },

    header: {
      fontSize: 30,
      fontWeight: 'bold',
      padding: 20,
      textAlign: 'center',
      backgroundColor: '#000',
      color: '#fff'
    },

    dateHeader: {
      fontSize: 20,
      fontWeight: 'bold',
      padding: 20,
      textAlign: 'left',
      color: '#fff',
      backgroundColor: '#283593'
    },

    eventCategory: {
        backgroundColor: '#03a9f4',
        textAlign: 'center',
        color: '#ffffff',
        padding: 3
    },

    eventTitle: {
        borderTopWidth: 0,
        textAlign: 'center',
        fontWeight: 'bold',
        padding: 3,
        fontSize: 18,
    },

    image: {
    },

    btn: {
        backgroundColor: 'green',
        padding: 10,
        color: '#fff',
        textAlign: 'center',
        flex: 1
    },

    price: {
        marginLeft: 10,
        fontSize: 16,
        flex: 1
    },

    time: {
      marginRight: 10,
      fontSize: 16,
      flex: 1,
      width: 35
    }

  });

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

Thanks!

EDIT: Updated code per the map suggestion, still not working. complaining about {events} only now.

EDIT 2: Updated with FULL code.

1 Answer 1

1

The component's render helpers, such as renderDates(), are returning _.each(...). _.each() returns its first argument so this is why you are receiving the error.

To illustrate:

const myObject = { a: 1 };
_.each(myObject) === myObject // true

I recommend you use Array.prototype.map() instead:

return this.state.dates.map((date) => (
  <View>...</View>        
));

If you use arrow functions like I did in the example above, there's no need to save a reference to this. this in the body of the function passed to map() will be bound to the instance of the component. You can then call other helper methods such as getImageStyles() like this.getImageStyles(...).

This is not related to your original question but the getApiData() method will not work. You can replace the function in the chain that handles responseJson with something like:

(responseJson) => {
  this.setState({
    dates: Object.entries(responseJson.events).map(([date, { events }]) => ({
      date,
      events,
    })),
    boxIndex: 0,
    showBox: false,
  });
}

You also need to to remove the this.state = {...} in componentDidMount(). Notice the warning in the docs that indicates you should "NEVER mutate this.state directly".

Sign up to request clarification or add additional context in comments.

4 Comments

Edited above with new code, same problem. Now it just does it for {events} instead.
Are you sure you're posting the full code? getApiData() returns undefined. I'm also not sure what createFragement() is but it's not necessary here. Finally, you should remove this.state = {...} in componentDidMount().
Not the full code, thought it would be enough...but i've posted the contents of my index.ios.js file
I am also getting the same error for github.com/kushmpatel/auth_React_Demo this demo. Can you please checkout this project and check it? I am learning react native and seriously have no idea where is the problem in my code?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.