5

I am new to react native and I was implemented a simple idea in my head. Basically, I am doing a 'todo list' like component which theres a add button below and items can be added. The problem arises after clicking on the add button and the list gets updated and the following xcode warning message appears. And I have realised, after implementing the ListView, that the app in the simulator slows down so much i couldn't even inspect. The alert popup would freeze the UI after some text are entered too, and the entire app needs to be built again since I couldn't do anything. Thanks for all the help!

Main component: SurveyQn

'use strict'

import React, { Component, StyleSheet, Text, TouchableHighlight, TextInput, View, ListView, AlertIOS } from 'react-native';

var LongButton = require('./LongButton.js');

class SurveyQn extends Component {

constructor(props) {
    super(props);

    this.state = {
        options: [{option: 'Pizza'}],
    };
}

componentWillMount() {
    this.dataSource = new ListView.DataSource({
        rowHasChanged: (row1, row2) => row1 !== row2
    })
}

_renderItem(item) {
    return (
        <LongButton 
            text={item.option} 
            onPress={() => {}} 
            //btnViewStyle={styles.buttonView}
            //btnTextStyle={styles.buttonText}
        />
    );
}

_addItem() {
    AlertIOS.alert(
        'Add new option',
        null,
        [
            {
                text: 'Add',
                onPress: (text) => {
                    var options = this.state.options;
                    options.push({option: text})
                    this.setState({ options: options})
                }
            },
        ],
        'plain-text'
    );
}

render(){
    var dataSource = this.dataSource.cloneWithRows(this.state.options);
    return (
        <View style={styles.container}>
            <TextInput
                style={styles.question}
                placeholder="Question title"
                placeholderTextColor="#4B667B"
                selectionColor="#4B667B"
                onChangeText={(text) => this.setState({text})}/>

            <View style={styles.listView}>
                <ListView
                    dataSource={dataSource}
                    renderRow={this._renderItem.bind(this)}/>

            </View>
                <TouchableHighlight 
                    onPress={this._addItem.bind(this)}
                    style={styles.buttonView}
                    underlayColor='rgba(0,0,0,0)'>
                    <Text style={styles.buttonText}>
                        Add option
                    </Text>
                </TouchableHighlight>
        </View>


    );
}

}

var styles = StyleSheet.create({ container: { width: 300, flex :1, }, listView: { flex: 1, }, question: { height: 30, fontSize: 20, fontWeight: "100", color: '#4B667B', marginTop: 10, marginBottom: 10, }, buttonView: { width: 300, paddingVertical: 9, borderWidth: 1, borderColor: '#F868AF', marginBottom: 13, }, buttonText: { textAlign: 'center', fontSize: 25, color: '#F868AF', fontWeight: '500' }, });

ListView item: LongButton

'use strict'

import React, { Component, StyleSheet, Text, TouchableHighlight, View, } from 'react-native';

class LongButton extends Component {

render(){
    return (
        <TouchableHighlight 
            onPress={this.props.onPress}
            style={this.props.btnViewStyle}
            underlayColor='rgba(0,0,0,0)'>
            <Text style={this.props.btnTextStyle}>
                {this.props.text}
            </Text>
        </TouchableHighlight>
    );

} }

module.exports = LongButton;

Xcode warning message upon adding item on alert

app[27881:11151280] the behavior of the UICollectionViewFlowLayout is not defined because: app[27881:11151280] the item height must be less than the height of the UICollectionView minus the section insets top and bottom values, minus the content insets top and bottom values. app[27881:11151280] The relevant UICollectionViewFlowLayout instance is <_UIAlertControllerCollectionViewFlowLayout: 0x7ff0685b1770>, and it is attached to ; layer = ; contentOffset: {0, 0}; contentSize: {0, 0}> collection view layout: <_UIAlertControllerCollectionViewFlowLayout: 0x7ff0685b1770>. 2016-04-06 07:50:01.545 decisionapp[27881:11151280] Make a symbolic breakpoint at UICollectionViewFlowLayoutBreakForInvalidSizes to catch this in the debugger.

Updates: I tried this but its not working either. Could it be the alert causing these problems? Its just taking forever to render the alert after clicking on the btn.

class SurveyQn extends Component {

constructor(props) { super(props);

   this.state = {
       options: [{option: 'Pizza'}],
       dataSource : new ListView.DataSource({
           rowHasChanged: (row1, row2) => row1 !== row2
       })
   };

}

componentWillMount() { var data = this.state.options; this.state.dataSource.cloneWithRows(data); }

_renderItem(item) { return ( {item.option} ); }

_addItem() { AlertIOS.alert( 'Add new option', null, [ { text: 'Add', onPress: (text) => { var options = this.state.options; options.push({option: text}) this.setState({ options: options}) } }, ], 'plain-text' ); }

render(){ return (

           <View style={styles.listView}>
               <ListView
                   dataSource={this.state.dataSource}
                   renderRow={this._renderItem.bind(this)}/>

           </View>
               <TouchableHighlight 
                   onPress={this._addItem.bind(this)}
                   style={styles.buttonView}
                   underlayColor='rgba(0,0,0,0)'>
                   <Text style={styles.buttonText}>
                       Add option
                   </Text>
               </TouchableHighlight>
       </View>


   );

} }

1 Answer 1

1

Before diving into complex EcmaScript notation, you can use simple notation. Here is a simple example of ListView. Please go through it and understand how it works.

var API = require('./API');
module.exports = React.createClass({
  getInitialState: function(){
    return {
      rawData: [],
      dataSource: new ListView.DataSource({
        rowHasChanged: (row1, row2) => row1 !== row2
      }),
      loaded: false,
    }
  },
  componentWillMount: function(){
    this.loadData();
  },
  loadData: function(){
    API.getItems()
    .then((data) => {
      this.setState({
        rawData: this.state.rawData.concat(data),
        dataSource: this.state.dataSource.cloneWithRows(data),
        loaded: true,
      });
    });
  },
  render: function(){
    return(
        <ListView 
          dataSource={this.state.dataSource}
          renderRow={this.renderItem}
          style={styles.listView}>
        </ListView> 
    );
  },
  renderItem: function(item){
    return (
      <View>
          <Text>Custom Item</Text>
      </View>
    );
  },
}

In API.js, I am fetching data from an API.

getItems: function(){
        var REQUEST_URL = 'http://api.example.org/item/get?api_key=xxxx;
        return fetch(REQUEST_URL)
            .then((response) => response.json())
            .then((responseData) => {
                return responseData.results.sort(sortByDate);
            });
    }

The code may not work, since I have not tested. But you can refer my sample project on github. Repo

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

2 Comments

I have already went through ListViews tutorials but do you have any idea where i have gone wrong instead?
@jomaint yes. There are multiple mistakes in your code. this.dataSource used in componentWillMount() is wrong. There is nothing in your react class called as dataSource. You need to declare datasource in getInitialState() or constructor. After that you may solve the remaining potential errors.

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.