score:6

Accepted answer

Never do setState in render. The reason you are not supposed to do that because for every setState your component will re render so doing setState in render will lead to infinite loop, which is not recommended.

checkData boolean variable is not needed. You can directly compare previous cost and current cost in componentWillReceiveProps, if they are not equal then assign cost to theData using setState. Refer below updated solution.

Also start using shouldComponentUpdate menthod in all statefull components to avoid unnecessary re-renderings. This is one best pratice and recommended method in every statefull component.

import React, { Component } from 'react';
import FormComponent from './FormComponent';
import PieGraph from './PieGraph';

const initialval = '8998998998';

class Dist extends Component {
  constructor() {
    this.state = {
      theData: ''
    };
    this.graphs(initialval);
  }

  componentWillReceiveProps(nextProps) {
    if (this.props.cost != nextProps.cost) {
      this.setState({
        theData: this.props.cost
      });
    }
  }

  shouldComponentUpdate(nextProps, nextState){
     if(nextProps.cost !== this.props.cost){
         return true;
     }
     return false;
  }
  graphs(val) {
    //Calls a redux action creator and goes through the redux process
    this.props.init(val);
  }

  render() {
    return (
      <div>
        <FormComponent onGpChange={recData => this.graphs(recData)} />
        {this.state.theData !== "" && <PieGraph theData={this.state.theData} />}
      </div>
    );
  }
}

PS:- The above solution is for version React v15.

score:2

You should not use componentWillReceiveProps because in most recent versions it's UNSAFE and it won't work well with async rendering coming for React.

There are other ways!

static getDerivedStateFromProps(props, state)

getDerivedStateFromProps is invoked right before calling the render method, both on the initial mount and on subsequent updates. It should return an object to update the state, or null to update nothing.

So in your case

...component code
static getDerivedStateFromProps(props,state) {
  if (this.props.cost == nextProps.cost) {
    // null means no update to state
    return null;
  }

  // return object to update the state
  return { theData: this.props.cost };
}
... rest of code

You can also use memoization but in your case it's up to you to decide. The link has one example where you can achieve the same result with memoization and getDerivedStateFromProps

For example updating a list (searching) after a prop changed You could go from this:

static getDerivedStateFromProps(props, state) {
    // Re-run the filter whenever the list array or filter text change.
    // Note we need to store prevPropsList and prevFilterText to detect changes.
    if (
      props.list !== state.prevPropsList ||
      state.prevFilterText !== state.filterText
    ) {
      return {
        prevPropsList: props.list,
        prevFilterText: state.filterText,
        filteredList: props.list.filter(item => item.text.includes(state.filterText))
      };
    }
    return null;
  }

to this:

import memoize from "memoize-one";

class Example extends Component {
  // State only needs to hold the current filter text value:
  state = { filterText: "" };

  // Re-run the filter whenever the list array or filter text changes:
  filter = memoize(
    (list, filterText) => list.filter(item => item.text.includes(filterText))
  );

  handleChange = event => {
    this.setState({ filterText: event.target.value });
  };

  render() {
    // Calculate the latest filtered list. If these arguments haven't changed
    // since the last render, `memoize-one` will reuse the last return value.
    const filteredList = this.filter(this.props.list, this.state.filterText);

    return (
      <Fragment>
        <input onChange={this.handleChange} value={this.state.filterText} />
        <ul>{filteredList.map(item => <li key={item.id}>{item.text}</li>)}</ul>
      </Fragment>
    );
  }
}

Related Query

More Query from same tag