1

I have the following:

import React from 'react';
import Chart from './chart.jsx';

import Form from "./form.jsx";

import data from "./data.js";

class App extends React.Component {  
    constructor(props) {
        super(props)

        this.holdingArray = [];

        this.state = {
            newGraphData: "",
            startingIndex: "",
            endingIndex: "",
            form: {
                range1: {
                    month: "",
                    year: ""
                },
                range2: {
                    month: "",
                    year: ""
                }
            }
        }

        this.findIndex = this.findIndex.bind(this);
        this.generateNewData = this.generateNewData.bind(this);
        this.getValue = this.getValue.bind(this);
    }

    findIndex(month, year) {
        var indexVal = data.findIndex(i => i.yyyy == year && i.month == month);
        return indexVal;
    }

    generateNewData(index1, index2) {
        for (var i = index1; i < data.length; i++) {
            if(i <= index2){
                this.holdingArray.push({ year: parseInt(data[i].month), value: parseInt(data[i].tmax_C) });
            }
        }

        this.setState({
            newGraphData: this.holdingArray
        })
    }

    getValue(e) {
        let target = e.target,
            condition = target.name,
            value = target.value;

        switch (condition) {
          case 'range1-m':
            this.setState({
                form.range1.month: value
            })
            break;
          case 'range1-y':
            this.setState({
                form.range1.year: value
            })
            break;

          case 'range2-m':
            this.setState({
                form.range2.month: value
            })
            break;

          case 'range2-y':
            this.setState({
                form.range2.year: value
            })
            break;
        }

        console.log(this.state);
    }

    render() {

        return (
            <section>
                <Chart data={dataTest} />
                <Form getValue={this.getValue} />
            </section>
        )
    }
}

export default App;

the "getValue" is called "onChange" in the following:

import React from 'react';

class Form extends React.Component {  
  render() {
    return (
      <form className="form">
        <div className="form__range">
            <select onChange={this.props.getValue} name="range1-m">
              <option>1</option>
              <option>2</option>
              <option>3</option>
            </select>
            <select onChange={this.props.getValue} name="range1-y">
              <option>1970</option>
              <option>1971</option>
              <option>1972</option>
            </select>
            <select onChange={this.props.getValue} name="range2-m">
              <option>1</option>
              <option>2</option>
              <option>3</option>
            </select>
            <select onChange={this.props.getValue} name="range2-y">
              <option>1973</option>
              <option>1974</option>
              <option>1975</option>
            </select>
        </div>
        <div className="form__selection">

        </div>
        <div className="form__submission">
            <button onClick={this.props.submitForm}>submit</button>
        </div>
      </form>
    )
  }
}

export default Form;

I am getting the following error, how can it be fixed? Is it possible to update one part of the state object at the time?

enter image description here

Aessandro
  • 5,517
  • 21
  • 66
  • 139

4 Answers4

2

You forgot to specify the key you want to update within the state.

this.setState({
  form: {
    ...this.state.form,
    range1: {
       ...this.state.form.range1,
       month: value,
    }
  }
})

Remember that setState is asynchronous and therefore you won't have access to it right away.

Hemerson Carlin
  • 7,354
  • 1
  • 27
  • 38
1

You are mutating your state object in your getValue method, which is not advisable.

Instead you should be doing the following.

getValue(e) {
        let target = e.target,
            condition = target.name,
            value = target.value;
           //This creates a new copy of the form object and 
           //does not change the existing object
           let newForm= JSON.parse(JSON.stringify(this.state.form));
           
        switch (condition) {
          case 'range1-m':
            newForm.range1.month: value
            break;
       ...
       }
        this.setState({
                form:newForm
            })
     ...
    }

As an aside, you should try not have too many nested levels in the shape of your state as this leads to complexities in making changes immutably. For hints on how to normalize your state shape, advise on managing the state shape in Redux is applicable.

Edit: For any concerns regarding using JSON.parse(JSON.stringify(obj)) to deep copy an object please check https://stackoverflow.com/a/5344074/2345964

Community
  • 1
  • 1
palsrealm
  • 5,083
  • 1
  • 20
  • 25
0

I don't think you can go deeper than the first level of object/arrays when setting state. Try chaning your switch function to look something more like:

case 'range1-m':
  const form = { ...this.state.form, range1: { ...this.state.fields.range1, month: value } }
  this.setState({ form })
  break
MEnf
  • 1,482
  • 1
  • 12
  • 18
0

You need to merge the current state with the new value.

var newForm = Object.assign({}, this.state.form, {
    range1: Object.assign({}, this.state.form.range1, {
        month: value
    })
});

this.setState({
    form: newForm
});
ruanmer
  • 31
  • 5