0

I'm having a lot of trouble updating the state of my child component, using props.

I have a parent component, called InputForm, which maintains a 2d array, which gets updated when the user fills out data in a form. This works correctly, however, I am trying to use this state variable to update the state of my child component, called Matrix. However, nothing I do seems to actually change the state of the Matrix component.

class InputForm extends Component {
  constructor(props) {
    super(props);
    this.matrix = React.createRef();
    this.state = {
      equation: null,
      integers: []
    };
  }

  addIntegers = v => {
    const newIntegers = this.state.integers.slice();
    newIntegers.push(v);
    this.setState({ integers: newIntegers });
    this.matrix.current.changeElements(this.state.integers);
  };

  render() {
    return (
      <div>
        <form onSubmit={this.mySubmitHandler}>
          <input
            type="text"
            name="equation"
            onChange={this.handleInputChange}
          />
        </form>
        <Matrix ref={this.matrix} values={this.state.integers} />
      </div>
    );
  }

class Matrix extends Component {
  state = {
    rows: 0,
    cols: 0,
    elements: [[]]
  };

  constructor(props) {
    super(props);
    this.setState({ elements: this.props.value });
  }

  changeElements = props => {
    this.setState({ elements: this.props.values });
    console.log(this.elements);
  };
Perplexityy
  • 561
  • 1
  • 9
  • 26
  • Think you can post this as a code sandbox? – dwjohnston Nov 18 '19 at 09:57
  • I will try, should I put all of my code in it? – Perplexityy Nov 18 '19 at 10:00
  • What state part are you trying to modify from the child? and where? – Alvaro Nov 18 '19 at 10:02
  • I've updated the code, I'm trying to update the Matrix's elements state in the InputForm's addIntegers method so they match that of the InputForm's integers state. However, I do not understand why it won't simply update the values when I pass them as props in the render method. – Perplexityy Nov 18 '19 at 10:12
  • Does this answer your question? [React js change child component's state from parent component](https://stackoverflow.com/questions/39041710/react-js-change-child-components-state-from-parent-component) – Jurrian Nov 18 '19 at 10:17

2 Answers2

1

In the parent component you are passing values as props

<Matrix ref={this.matrix} values={this.state.integers} />

while in the Matrix you are accessing:

constructor(props) {
    super(props);
    this.setState({ elements: this.props.value });
  }

where this.props.value is not there, you should access the this.props.values

Saqib Naseeb
  • 731
  • 1
  • 9
  • 21
0

Because, this.setState (...) is asynchronous function. if you want to call this.matrix.current.changeElements(this.state.integers); function after updated the parent state, set the second argument of this.setState (...) to the callback function.

This is the fixed code

class InputForm extends Component {
...
  addIntegers = v => {
    const newIntegers = this.state.integers.slice();
    newIntegers.push(v);
    this.setState({ integers: newIntegers }, () => {     // use callback
        this.matrix.current.changeElements(this.state.integers);
    });
  };
...
class Matrix extends Component {
  constructor(props) {
    super(props);
    this.state = {
       rows: 0,
       cols: 0,
       elements: this.props.value || [[]] // try like this.
    };
  }

  changeElements = props => {
    // this.setState({ elements: this.props.values }); // wrong
    this.setState({ elements: props.values }, () => {
       console.log(this.state.elements);
    }); // maybe like this
  };

This is a simple example.

class App extends React.Component {
  constructor(props) {
    super(props);
    this.child = React.createRef();
    this.state = {
      value: "aaa",
    }
  };

  updateChild = () => {
    this.setState({value: "bbb"}, () => {
      this.child.current.changeElements(this.state.value);
    })
  };
  
  render() {
    return (
      <div>
        <button onClick = {this.updateChild} > Click here </button>
        <Child ref={this.child} values={this.state.value} />
      </div>
    );
  }
}

class Child extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: this.props.values,
    };
  }

  changeElements = value => {
    this.setState({ value });
    console.log(value);
  };
  
  render() {
    console.log(this.state.value)
    return (
      <div>{this.state.value}</div>
    );
  }
}

ReactDOM.render( < App / > , document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>
syjsdev
  • 1,326
  • 1
  • 9
  • 22