chapeljuice
chapeljuice

Reputation: 886

React Native: Child ListView will not update after element in parent is changed

I can't seem to get my ListView to update.

I have a parent container with a toggle switch (<SegmentedControls />). When the user clicks that toggle switch I'd like the ListView in the child component to update using the updated reservationListSelectedOption state value.

What am I missing?

Code here: https://gist.github.com/chapeljuice/69483ab0bde13346de024d4e4a9753f0

Upvotes: 0

Views: 288

Answers (3)

chapeljuice
chapeljuice

Reputation: 886

Actually I found a solution, thanks to both thinhvo0108 and Matt Aft for helping me get there.

Here is my revised componentWillReceiveProps function, which combined with fixed dataSource is now updating the ListView correctly:

componentWillReceiveProps (nextProps) {
  if ( nextProps.reservationListStatus === "Past Reservations" ) {
    this.setState({
      dataSource: ds.cloneWithRows(reservationData.previous)
    })
  } else {
    this.setState({
      dataSource: ds.cloneWithRows(reservationData.current)
    })
  }
  console.log( 'nextProps.reservationListStatus: ' + nextProps.reservationListStatus );
}

I updated my gist as well with the working code: https://gist.github.com/chapeljuice/69483ab0bde13346de024d4e4a9753f0

Upvotes: 0

thinhvo0108
thinhvo0108

Reputation: 2232

Actually, there's something wrong in the way you set your dataSource, in your constructor, you set it for the first time with: new ListView.DataSource({}) (this should not be changed later, because this is just kind of dummy thing, no data passed to it yet)

However, later you reset that state with : dataSource: this.state.dataSource.cloneWithRows(reservationData.previous)

=> (Here it has the cloneWithRows, so it will have data now => which means the this.state.dataSource "dummy-frame" itself has been changed, and the next execution of .cloneWithRows will fail - will not have the .cloneWithRows function anymore)

======> SOLUTION:

In my opinion, you can do:

In cardList.js:

// Put the data-source ds here, which won't be changed
var ds = new ListView.DataSource({rowHasChanged: (row1, row2) => row1 !== row2});

class CardList extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      reservationListStatus: this.props.reservationListStatus,
      dataSource: ds.cloneWithRows(/* PUT YOUR INITIAL reservationData, OR JUST a blank array '[]' will be fine*/),
    };
  }

..and later on, you just need to use ds.cloneWithRows(YOUR_NEW_RESERVATION_DATA) (always keep the ds unchanged), something like this:

  getReservationData() {
    if ( this.props.reservationListStatus === "Previous Reservations" ) {
      this.setState({
        dataSource: ds.cloneWithRows(reservationData.previous)
      })
    } else {
      this.setState({
        dataSource: ds.cloneWithRows(reservationData.current)
      })
    }
    console.log(this.state)
  }

That is the way you should do, but if it doesn't work yet, please post here some errors you encounter, thanks

Upvotes: 1

Matt Aft
Matt Aft

Reputation: 8936

Try adding componentWillReceiveProps to your child component. It would look something like this:

  componentWillReceiveProps(nextProps) {
    if (this.props.options !== nextProps.options) {
      this.setState({ reservationListSelectedOption: nextProps.options[0] });
    }
  }

Upvotes: 0

Related Questions