0

My app has a list view that render a list of items.

Screenshot

Every click of my child component triggers a change in state value

{ selected: !this.state.selected }

In the image above I have selected 2 child items, how can I access their value in my parent component?

For instance,

Big Data: true
IoT: true

This is my parent snippet, Hosted on Github too

import InterestItem from './InterestItem';

class AddInterest extends Component {

  componentWillMount() {
    this.createDataSource(this.props);
  }

  componentWillReceiveProps(nextProps) {
    this.createDataSource(nextProps);
  }

  createDataSource({ items }) {
    const ds = new ListView.DataSource({
      rowHasChanged: (r1, r2) => r1 !== r2
    });
    this.dataSource = ds.cloneWithRows(items);
  }

  //return arrays of event from events
  renderRow(item) {
    return <InterestItem item={item} icon={computer} />;
  }

  render() {
    const { centerEverything, skeleton, container, textContainer, contentContainer, listViewContainer,
      titleContainer, descContainer, title, desc, submitContainer, submitTitle } = styles;
    return (
      <View style={[container]}>
        <View style={[centerEverything, textContainer]}>
          <View style={titleContainer}>
            <Text style={[title]}>What kind of events are you interest in?</Text>
          </View>
          <View style={descContainer}>
            <Text style={[desc]}>You'll see more events from the categories you choose.</Text>
          </View>
        </View>

        <View style={[contentContainer]}>
          <ListView
            enableEmptySections
            contentContainerStyle={listViewContainer}
            dataSource={this.dataSource}
            renderRow={this.renderRow}
          />
        </View>

        <View style={[centerEverything, {paddingBottom: 10}]}>
          <View style={[centerEverything, submitContainer]}>
            <Text style={submitTitle}>Submit</Text>
          </View>
        </View>

      </View>
    )
  }
}

This is my child component, Hosted on GitHub too

class InterestItem extends Component {

  state = {
    selected: false
  }

  render() {
    const { skeleton, centerEverything, container, textStyle } = styles;
    return(
      <TouchableWithoutFeedback onPress={() => this.setState({ selected: !this.state.selected })}>
        <View style={[centerEverything, container, { backgroundColor: this.state.selected ? '#635eb4' : '#e7e7e7'}]}>
          {this.props.icon}
          <Text style={textStyle}>{this.props.item[0]}</Text>
        </View>
      </TouchableWithoutFeedback>
    )
  }
}

Upon request from @freesoul, here's the child instances (considering I have 8 children) enter image description here

3
  • Consider a single instance of InterestItem, what can be the value of this.props.item? Can you post an example? Commented Nov 27, 2016 at 12:00
  • @free-soul I have added the requested information Commented Nov 27, 2016 at 12:08
  • 2
    My suggestion is that you should maintain the state of children in your parent; something like state = { cars: false, bigData: true, hackintosh: false, iot: true, ... }. Commented Nov 27, 2016 at 12:29

1 Answer 1

2

Following up on @free-soul, I would do the following modifications to your code:

constructor(){
    this.state = {
    //...
        rowStates: {} // Holds the state for each row, identified by the uid property (I'm assuming it is unique, otherwise use some other value)
    }
    this.renderRow = this.renderRow.bind(this);
    this.rowUpdated = this.rowUpdated.bind(this);
}
renderRow(item) {
   // Adds a callback so that we know when an element has been pressed
    return <InterestItem item={item} icon={computer} onPress={() => this.rowUpdated(item)}/>;
}

rowUpdated(item){
     let rowStates = {...this.state.rowStates}; // Make a copy of the object
     rowStates[item.uid] = !rowStates[item.uid];  // If the item is not in the object, !undefined will be evaluated, which results in true, so the operation is safe
     this.setState({rowStates});
}

Then, your child component should look like this:

class InterestItem extends Component {

  state = {
    selected: false
  }

  render() {
    const { skeleton, centerEverything, container, textStyle } = styles;
    return(
      <TouchableWithoutFeedback onPress={() => {this.setState({ selected: !this.state.selected }); if(this.props.onPress) this.props.onPress(this.props.item)}}>
        <View style={[centerEverything, container, { backgroundColor: this.state.selected ? '#635eb4' : '#e7e7e7'}]}>
          {this.props.icon}
          <Text style={textStyle}>{this.props.item[0]}</Text>
        </View>
      </TouchableWithoutFeedback>
    )
  }
}

Hope it helps

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

3 Comments

I'm afraid rowStates = {} is invalid, react native complains about an error during runtime. State cannot be null?
Thanks for the answer, it was very helpful, though there are 2 mistakes. rowStates: {} and inside renderRow onPress method, we should return in fat arrow function, onPress={() => rowUpdated(item)} otherwise the app will run the method automatically
Uh, sorry! Didn't notice when writing. I've edited the answer to correct the mistakes.

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.