bkula
bkula

Reputation: 559

React componentWillReceiveProps not updating state

I've got this React parent component here. The children components at this point are just returning dropdown menus. I expected that componentWillReceiveProps would update the state here, which in turn should be passed to StopList as props. However, when state.selectedSub is changed through handleSubSelect, nothing happens and StopList doesn't receive any props.

Is my mistake with the asynchronous nature of componentWillReceiveProps? Is it in the wrong place in my code? Am I using the wrong lifecycle method?

// We're controlling all of our state here and using children
// components only to return lists and handle AJAX calls.

import React, { Component } from 'react';
import SubList from './SubList';
import StopList from './StopList';

class SubCheck extends Component {

  constructor (props) {
    super(props);
    this.state = {
        selectedSub: '--',
        selectedStop: null,
        stops: ['--'],
    };
    this.handleSubSelect.bind(this);
    this.handleStopSelect.bind(this);
    }

    // We want the user to be able to select their specific subway
    // stop, so obviously a different array of stops needs to be 
    // loaded for each subway. We're getting those from utils/stops.json.
    componentWillReceiveProps(nextProps) {
        var stopData = require('../utils/stops');
        var stopsArray = [];
        var newSub = nextProps.selectedSub
        for(var i = 0; i < stopData.length; i++) {
            var stop = stopData[i];

            if (stop.stop_id.charAt(0) === this.state.selectedSub) {
                stopsArray.push(stop.stop_name);
            }
        }
        if (stopsArray.length !== 0 && newSub !== this.state.selectedSub) {
            this.setState({stops: stopsArray});
        }
    }

    handleSubSelect(event) {
        this.setState({selectedSub:event.target.selectedSub});
    }

    handleStopSelect(event) {
        this.setState({selectedStop:event.target.selectedStop})
    }

    render() {
        return (
            <div>
                <SubList onSubSelect={this.handleSubSelect.bind(this)}/>
                <StopList stops={this.state.stops} onStopSelect={this.handleStopSelect.bind(this)}/>
            </div>
        );
    }
}

export default SubCheck;

Upvotes: 1

Views: 2543

Answers (1)

Jake Haller-Roby
Jake Haller-Roby

Reputation: 6427

You are duplicating data, and causing yourself headaches that aren't necessary.

Both selectedSub and selectedStop are being stored as props and as state attributes. You need to decide where this data lives and put it in a singular location.

The problem you are encountering entirely revolves round the fact that you are changing the state attribute and expecting this to trigger a change to your props. Just because they share a name does not mean they are the same value.

Upvotes: 2

Related Questions