Adrian Pascu
Adrian Pascu

Reputation: 1039

React - child component not updating when receiving new props

I have to create a dot page indicator component in react. I first created a dot component, then the actual indicator component . But I have a problem with it.

The state of the indicator component depends on the props that it receives and it as well has to set the state of the individual dots passing down props. To update the state when new props come in I've used componentWillReceiveProps

class PageIndicator extends React.Component{

constructor(props){
    super(props);
    let pills = [];
    for(var i = 0;i<props.size;i++) //Create an array of all the pills required to create the page indicator
        if(i == this.props.activeIndice) //Check which of the pills is the active one - active is true
            pills.push(<PageIndicatorPill key={i} active={true}/>);
        else
            pills.push(<PageIndicatorPill key={i} active={false}/>);

    this.state = {pills:pills};
}

componentWillReceiveProps(nextProps){
    let pills = [];
    for (var i = 0; i < nextProps.size; i++) //Update the indicator
        if (i == nextProps.activeIndice) //Check which of the pills is the active one - active is true
            pills.push(<PageIndicatorPill key={i} active={true} />);
        else
            pills.push(<PageIndicatorPill key={i} active={false} />);

    this.setState({ pills: pills });
}

And here is the dot component

class PageIndicatorPill extends React.Component{


    constructor(props){

        super(props);
        if(this.props.active)
            this.state={image : onState};
        else
            this.state = { image: offState };

        this.style = {
            backgroundImage:`url(${this.state.image})`,
            marginRight:'10px', 
            height:"32px", 
            width:"32px" ,
            display:"inline-block"};

    }

    componentWillReceiveProps(nextProps){
        if (nextProps.active)
            this.setState({ image: onState });
        else
            this.setState({image : offState});
    }

If I go ahead and console log the states, they update, but the problem is that the component doesn't seem to re-render accordingly and I can't figure out why. Can you help me out please?

Upvotes: 1

Views: 178

Answers (1)

Steve Vaughan
Steve Vaughan

Reputation: 2189

Your state is updating, however you only set your styles in the constructor of your PageIndicatorPill component. this.style would need to be updated within the componentWillReceiveProps method.

However.. This can be simplified a lot from the example you have provided. There is no need to mirror the active prop in state as image. You could do something like:

class PageIndicatorPill extends React.Component{

  getStyle() {
    const { active } = this.props;
    return {
        backgroundImage: `url(${active ? onState : offState})`,
        marginRight: '10px', 
        height: '32px', 
        width: '32px',
        display: 'inline-block'
    };
  }

  render() {
    return (
      <div style={this.getStyle()} />
    );
  }
}

You didn't post a render function so this example is just a simple demonstration of using props directly to get the styles, but hopefully the above makes sense.

Your other component can also be simplified and not need state...

class PageIndicator extends React.Component{

  getPills() {
    const { size, activeIndice } = this.props;
    let pills = [];
    for (let i = 0; i < size; i++) {
      pills.push(
        <PageIndicatorPill key={i} active={i === activeIndice} />
      );
    }
    return pills;
  }

  render() {
    return (
      <div>
        {this.getPills()}
      </div>
    );
  }
}

Upvotes: 1

Related Questions