-2

I have been playing around with an error which I am not able to understand. Here is the code i am using for rendering a page.

export class ResourceEdit extends React.Component {

  constructor(props) {
   super(props);
  this.state = {"resource" : ""}
  }

  getInitialState() {
    return {successVisible: false};
  }

  componentDidMount() {
    this.loadData();
  }

  componentDidUpdate(prevProps) {
    console.log("ResourceEdit: componentDidUpdate", prevProps.params.id, this.props.params.id);
    if (this.props.params.id != prevProps.params.id) {
      this.loadData();
    }
  }

  loadData() {
    $.ajax('/api/resources/' + this.props.params.id) .done(function(resource) {
      this.setState(resource);
    }.bind(this));

  }

  onChangeCategory(e) {
    this.setState({category: e.target.value});
  }
  onChangeSubcategory(e) {
    this.setState({subcategory: e.target.value});
  }
  onChangeProduct(e) {
    this.setState({product: e.target.value});
  }
  onChangeSolution(e) {
    this.setState({solution: e.target.value});
  }
  onChangeWeight(e) {
    this.setState({weight: e.target.value});
  }
  onChangeNSOC(e) {
    this.setState({nsoc: e.target.value});
  }
  onChangeStatus(e) {
    this.setState({status: e.target.value});
  }

  onChangeDateproductadded(e) {
    this.setState({date_product_added: e.target.value});
  }
  onChangeDesignstatus(e) {
    this.setState({design_status: e.target.value});
  }
  onChangeDesigncombined(e) {
    this.setState({design_combined: e.target.value});
  }
  onChangeImplementstatus(e) {
    this.setState({implement_status: e.target.value});
  }
  onChangeImplementcombined(e) {
    this.setState({implement_combined: e.target.value});
  }
  onChangeOperatestatus(e) {
    this.setState({operate_status: e.target.value});
  }
  onChangeOperatecombined(e) {
    this.setState({operate_combined: e.target.value});
  }
  submit(e) {
    e.preventDefault();
    var resource = {
      subcategory: this.state.subcategory,
      category: this.state.category,
      product: this.state.product,
      solution: this.state.solution,
      weight: this.state.weight,
      nsoc: this.state.nsoc,
      status: this.state.status,
      date_product_added: this.state.date_product_added,
      design_status: this.state.design_status,
      design_combined: this.state.design_combined,
      implement_status: this.state.implement_status,
      implement_combined: this.state.implement_combined,
      operate_status: this.state.operate_status,
      operate_combined: this.state.operate_combined
    }

    $.ajax({
      url: '/api/resources/' + this.props.params.id, type: 'POST', contentType:'application/json',
      data: JSON.stringify(resource),
      dataType: 'json',
      success(resource) {
        this.setState(resource);
        this.showSuccess();
      }
    });
  }

  render() {
    var success = (
      <Alert bsStyle="success" onDismiss={this.dismissSuccess} dismissAfter={5000}>
        Resource saved to DB successfully.
      </Alert>
    );

    return (
      <div style={{maxWidth: 600}}>
        <Panel header={"Edit resource: " + this.props.params.id}>
          <form onSubmit={this.submit}>
            <Input type="text" label="Category" value={this.state.category} onChange={this.onChangeCategory}/>
            <Input type="text" label="Sub Category" value={this.state.subcategory} onChange={this.onChangeSubcategory}/>
            <Input type="text" label="Product" value={this.state.product} onChange={this.onChangeProduct}/>
            <Input type="text" label="Solution" value={this.state.solution} onChange={this.onChangeSolution}/>
            <Input type="text" label="Weight" value={this.state.weight} onChange={this.onChangeWeight}/>
            <Input type="text" label="NSOC" value={this.state.nsoc} onChange={this.onChangeNSOC}/>
            <Input type="text" label="Status" value={this.state.status} onChange={this.onChangeStatus}/>
            <Input type="text" label="Date" value={this.state.date_product_added} onChange={this.onChangeDateproductadded}/>
            <Input type="text" label="Design Status" value={this.state.design_status} onChange={this.onChangeDesignstatus}/>
            <Input type="text" label="Design Players" value={this.state.design_combined} onChange={this.onChangeDesigncombined}/>
            <Input type="text" label="Implement Status" value={this.state.implement_status} onChange={this.onChangeImplementstatus}/>
            <Input type="text" label="Implement Players" value={this.state.implement_combined} onChange={this.onChangeImplementcombined}/>
            <Input type="text" label="Operate Status" value={this.state.operate_status} onChange={this.onChangeOperatestatus}/>
            <Input type="text" label="Operate Players" value={this.state.operate_combined} onChange={this.onChangeOperatecombined}/>
          <ButtonToolbar>
              <Button type="submit" bsStyle="primary">Submit</Button>
              <Link className="btn btn-link" to="/home">Back</Link>
            </ButtonToolbar>
          </form>
        </Panel>
        {this.state.successVisible ? success : null}
      </div>
    );
  }
}

I am getting an error on page load which says Uncaught Error: setState(...): takes an object of state variables to update or a function which returns an object of state variables. at invariant (eval at

Please someone help me figure out what is wrong in this code. Thanks in advance..

nelalx
  • 89
  • 2
  • 9
  • *at ...* ?????? – Jonas Wilms Jul 29 '17 at 13:45
  • 3
    Clearly in one of the places you call `setState` you're not passing in *"an object of state variables to update or a function which returns an object of state variables"*. So...debug and find out why not. Debugging is a fundamental, beginning skill, not an advanced one. It's one of the first things to learn. – T.J. Crowder Jul 29 '17 at 13:46
  • 1
    What is return in ajax response ? json ? please edit question & add response of api – Kaushal Jul 29 '17 at 13:46
  • Also note that `this` in the second of your `ajax` callbacks (in `submit`) is not a reference to your component. More [*How to access the correct `this` / context inside a callback?*](http://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-context-inside-a-callback) (It is in your first because you used `bind`. I would use arrow functions instead.) – T.J. Crowder Jul 29 '17 at 13:48
  • inside the done method of ajax, change `this.setState(resource)` to `this.setState({resource})` – Nagaraj Tantri Jul 29 '17 at 13:48
  • @NagarajTantri: Quite possibly. We can't know, because we don't know what `resource` is, and whether it's meant to be used directly as `state.resource`. – T.J. Crowder Jul 29 '17 at 13:49
  • @T.J.Crowder Thats why the comment, don't know his ajax return value ;) – Nagaraj Tantri Jul 29 '17 at 13:50

1 Answers1

-1

Whenever you call this.setState() in a function, make sure to bind it with this. In this example, you might need to bind all of the onChange functions with this.

You can bind them in the constructor then you don't need to worry about it or bind it in the render function.

constructor(props) {
  super(props);
  this.state = {"resource" : ""}      

  this.loadData = this.loadData.bind(this)
  this.onChangeCategory = this.onChangeCategory.bind(this)
  this.onChangeSubcategory = this.onChangeSubcategory.bind(this)
  // and more methods to bind...
}

With this kind of practice you don't need to bind(this) in the ajax call which can make the code clean and neat.

Hope this helps!

Linuk
  • 91
  • 1
  • 3