Search code examples
reactjstypescriptcallbacksetstatereact-component

React JS : Calling Child component method within parent component (React with typescript)


I am trying to create a custom number picker component and trying to add it to the components wherever it is needed. But When I am trying to fetch the number picker value in the Parent component , I am getting the older value . Can someone help me with this?

Number Picker Component

import * as React from "react";

interface IState {
  value: number;
}

interface IProps {
  setValue(val: number): void;
}

class NumberPicker extends React.Component<IProps, IState> {
  constructor(props: any) {
    super(props);
    this.state = {
      value: 0
    };
  }

  public doDecrement = () =>
    // DECREMENT CODE
    {
      if (this.state.value < 1) {
        console.log("LESS THAN O");
      } else {
        this.setState({
          value: this.state.value - 1
        });
        this.props.setValue(this.state.value);
      }
    };

  public doIncrement = () =>
    // INCREMENT CODE
    {
      this.setState({
        value: this.state.value + 1
      });
      this.props.setValue(this.state.value);
    };

  public handleChange = (
    e: React.ChangeEvent<HTMLInputElement> // CHANGE HANDLER
  ) => {
    const val = parseInt(e.target.value);
    this.setState({ value: val });
  };

  public render() {
    return (
      <div>
        <button
          onClick={this.doDecrement}
          className="fa fa-minus fa-inverse fa-2x"
        />
        <input
          type="text"
          className="number"
          value={this.state.value}
          onChange={this.handleChange}
        />
        <button
          onClick={this.doIncrement}
          className="fa fa-plus fa-inverse fa-2x"
        />
      </div>
    );
  }
}
export default NumberPicker;

PARENT COMPONENT CODE

import * as React from "react";
import NumberPicker from "./NumberPicker";

interface IState {
  val: number;
}

interface IProps {}

class Parent extends React.Component<IProps, IState> {
  constructor(props: any) {
    super(props);
    this.state = {
      val: 0
    };
  }

  handleVal = (value: number) => {
    this.setState({ val: value }, () => console.log(this.state.val));
  };

  render() {
    return (
      //Some fields along with the below numberpicker
      <NumberPicker setValue={this.handleVal} />
    );
  }
}

export default Parent;

I have tried using setState's callback function as well, but it does not seem to be working . Parent component always shows the older value.How will I get the updated value of the NumberPicker inside parent? Help would be appreciated!


Solution

  • React's setState is asynchronous, and because of that this.props.setValue function is going to be called before setState has updated your state in child Numberpicker component. This is why an old value is passed to the parent component.

    Instead you can call this.props.setValue inside setState's callback function.

     public doIncrement = () =>
        // INCREMENT CODE
        {
          this.setState({
            value: this.state.value + 1
          }, () => {
                  this.props.setValue(this.state.value);
             });
    
        };
    
    public doDecrement = () =>
        // DECREMENT CODE
        {
          if (this.state.value < 1) {
            console.log("LESS THAN O");
          } else {
            this.setState({
              value: this.state.value - 1
            }, () => {
                  this.props.setValue(this.state.value);
               });
          }
        };