Grzes Slania
Grzes Slania

Reputation: 602

Loop with componentDidUpdate

I am passing a self invoking function from App Component into getBgColor function of WeatherForecast Component. This grabs a value from the child component WeatherForecast and passes it into App Component to update this.state.appColorClass.

*getBgColor function is inside componentDidUpdate() which creates a loop and crashes the broweser. New to react and not sure how to solve this.

export default class App extends Component {
  constructor(props) {
    super(props);

    this.state = { appColorClass: 'app-bg1' };
  }

  setAppColor(colorClass) {
    alert("set className");
    this.setState({ appColorClass: colorClass });
  }

  render() {
    return (
    <div className={"app-container " + this.state.appColorClass}>
      <div className="main-wrapper">

          <WeatherForecast getBgColor={color => this.setAppColor(color)} />

      </div>   
    </div> 
    );
  }
}


class WeatherForecast extends Component {
  componentDidUpdate() {
    console.log('Component DID UPDATE!')
      //The function `setAppColor` from `App` component is passed into `getBgColor`
      this.props.getBgColor(this.appColor(this.props.weather));
  }

  appColor(weatherData) {
    console.log("app color working");

    let temp = 0;
    if ( typeof weatherData === 'undefined' || weatherData === null ) {
      console.log(" initial Color went through");
      return 'app-bg1';
    }
    temp = Math.round(weatherData.list[0].main.temp - 273.15);
    if (temp <= -30) {
        return "app-bg1";
    }
    if (temp >= -29 && temp <= -21) {
        return "app-bg2";
    }
    if (temp >= -20 && temp <= -11) {
        return "app-bg3";
    }
    if (temp >= -10 && temp <= 4) {
        return "app-bg4";
    }
    if (temp >= 5 && temp <= 15) {
        return "app-bg5";
    }
    if (temp >= 16 && temp <= 24) {
        return "app-bg6";
    }
    if (temp >= 25 && temp <= 32) {
        return "app-bg7";
    }
    if (temp >= 33 && temp <= 38) {
        return "app-bg8";
    }
    if (temp >= 39) {
        return "app-bg9";
    }
  }

  render() {

    return (
      <div className="text-center col-xs-12">
         <h1 id="temp">{this.displayTemp(this.props.weather)}<sup>&deg;</sup></h1>
         <h1>{this.displayCity(this.props.weather)}</h1> 
      </div>
    );
  }
}

Upvotes: 0

Views: 781

Answers (2)

Grzes Slania
Grzes Slania

Reputation: 602

I ended up going with Johnny Klironomos's suggestion which returned true or false according to the Property value in shouldComponentUpdate.

*this.props.weather is undefined once the app loads because the user needs to pick a city to view its weather.

shouldComponentUpdate(nextProps) {
    if(this.props.weather === 'undefined'){
      return true
    }
    return this.props.weather !== nextProps.weather
  }

Upvotes: 0

BradByte
BradByte

Reputation: 11093

The loop is recursive because after the WeatherForecast component mounts (updating) it calls the getBgColor prop, which sets parent state, which triggers a child update, which calls getBgColor... and you get the picture.

Honestly, I would probably advise moving the logic around a little... since weather is passed in as a prop and then the color is passed back up, it would seem more "React" like to handle that in the parent component. It's simpler to follow when data flows downstream. Assuming your requirements lead you to this position, adding a simple check in the setAppColor would solve the issue.

setAppColor(colorClass) {
  alert("set className");
  // only set state if it's changing
  if (colorClass != this.state.appColorClass) {
    this.setState({ appColorClass: colorClass });
  }
}

Upvotes: 1

Related Questions