Piero
Piero

Reputation: 9273

Component not update after updating props

My question is why the component did not update after update the props. This is my code that explain me well:

export default class App extends React.Component {

    constructor(props) {
        super(props);
        this.topWeakSlotsData = {};
        this.topWeakSlotsData['loading'] =  true;
        this._fetchWeeklyWeakSlots();
    }

    _fetchWeeklyWeakSlots() {
      var _this = this;
      fetch("...")
      .then(function(response) {
          return response.json()
      }).then(function(json) {

          _this._elaborateTopWeakSlots(json['return']);

      }).catch(function(ex) {
          console.log('parsing failed', ex)
      })
    }

    _elaborateTopWeakSlots(data) {
      ...
      this.topWeakSlotsData['options'] = {
        ...
      }

      this.topWeakSlotsData['loading'] =  false;

    }

    render() {
      return (
        <HighchartContainer data = {this.topWeakSlotsData} container ="chart1" />
      )
    }
}

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

   shouldComponentUpdate(nextProps, nextState) {
     console.log("should update");
     return true;
   }

   componentWillReceiveProps(nextProps) {
     console.log(nextProps);
   }

   renderLoading() {
      return (
          <div>
           <Loader />
          </div>
      );
   }

   renderChart() {
      return (
         <div>
            <Highchart container = {this.props.container} options = {this.props.data.options}/>
         </div>
       );
   }

   render() {
      return (
         <div>
           {this.props.data.loading ? this.renderLoading() : this.renderChart()}
         </div>
      );
   }
}

As you can see when the fetch finish I change the loading from true to false and I fill also the options array, but shouldComponentUpdate or componentWillReceiveProps is not called and the component is not refreshed, what I wrong?

Upvotes: 0

Views: 190

Answers (2)

Alex Young
Alex Young

Reputation: 4039

The App component will only re-render the HighChartContainer component when either App's props or state changes. You are currently storing topWeakSlotsData as a class property, so the component will not update when it changes. You need to store it as state on App.

export default class App extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
            topWeakSlotsData: {
                loading: true
            },
            lowWeakSlotsData: {
                loading: false // or whatever data you want here
            }
        }
        this._fetchWeeklyWeakSlots();
    }

    _fetchWeeklyWeakSlots() {
      var _this = this;
      fetch("...")
      .then(function(response) {
          return response.json()
      }).then(function(json) {    
          _this._elaborateTopWeakSlots(json['return']);

      }).catch(function(ex) {
          console.log('parsing failed', ex)
      })
    }

    _elaborateTopWeakSlots(data) {
        this.setState({
            topWeakSlotsData: {
               loading: false,
               options: data.options // or wherever else
            }
        }
    }

    render() {
      return (
        <HighchartContainer data = {this.state.topWeakSlotsData} container ="chart1" />
      )
    }
}

Edit

As the other answer points out you can refactor you _fetchWeeklyWeakSlots method to use arrow/lambda functions, e.g.

_fetchWeeklyWeakSlots() {  
    fetch("...")
        .then(response => response.json())
        .then(json => json['return'])
        .then(_elaborateTopWeakSlots)
        .catch(ex => {
            console.log('parsing failed', ex)
        });
    }

Upvotes: 3

Lance Jernigan
Lance Jernigan

Reputation: 226

Once your fetch promise resolves, you will need to update your state by passing your response to this.setState()

var _this = this

fetch(url)
    .then( function(response) { return response.json() }) // parse our response into json
    .then( function(json) { _this.setState({json: json}) } // set our state based on our parsed response

Once your state has been updated, you can reference {this.state.json} from within your component.

Bonus If you use ES6 arrow functions: args => { //do stuff here } you don't need var _this = this because of how this is handled.

The above example becomes:

fetch(url)
    .then( response => response.json() )
    .then( json => this.setState({ json: json })

Upvotes: 2

Related Questions