Search code examples
javascriptreactjssetstate

I am updating my state using this.setState but still i am recieving the old values in render()


class EditLocation extends Component {
  constructor(props) {
   super();
    this.state = {
      LocationId: '',
      locationOptions: [],
    }
    this.baseState = this.state;
    this.findLocationById = this.findLocationById.bind(this);

}
findLocationById = (locationId) => {
  let locationOptions = [];
  if (locationId <= 0) {
    setTimeout(()=>{
      this.setState(this.baseState);
      locationOptions.push(
        <CustomInput
        type="checkbox"
        id={value.LocationTypeId}
        key={value.LocationTypeId}
        value={value.LocationTypeId}
        defaultChecked={false}
        label={`${value.LocationTypeName}`}
        className="mb-0"
        onChange={this.handleCheckbox.bind(this)}
      />
      )
      this.setState({locationOptions:locationOptions})
    },200)
    else {
      setTimeout(() => {
      let location = this.props.store.selectedLocation;
      this.props.store.LocationTypes.forEach((value)=>{
        if(location.LocationTypes ? 
         location.LocationTypes.includes(value.LocationTypeId): false)
        {
          locationOptions.push(
            <CustomInput
            type="checkbox"
            id={value.LocationTypeId}
            key={value.LocationTypeId}
            value={value.LocationTypeId}
            defaultChecked={true}
            label={`${value.LocationTypeName}`}
            className="mb-0"
            onChange={this.handleCheckbox.bind(this)}
          />
          )
        }
        else
        {
          locationOptions.push(
            <CustomInput
            type="checkbox"
            id={value.LocationTypeId}
            key={value.LocationTypeId}
            value={value.LocationTypeId}
            defaultChecked={false}
            label={`${value.LocationTypeName}`}
            className="mb-0"
            onChange={this.handleCheckbox.bind(this)}
          />
          )
        }
      })
    this.setState({
       LocationId: location.LocationId,
       locationOptions: locationOptions,
    })
   

   render(){
  return (
   <div>
    <Modal>
      <Form>
         <FormGroup>
           <input
            value={this.state.LocationId}
            type="text"
            name="Location"
            id="Location"      
           />
         </FormGroup>
         <FormGroup>
           {console.log(this.state.locationOptions)} // showing updated state value
           {this.state.locationOptions} // showing previous state.locationOptions value
         </FormGroup>
        </Form>
    </Modal>
   </div>
   )
}

}

console.log() inside the render is updating the value by my checks on customInput are not updating. I need to either reopen the modal or reload the whole program to see updates. Any solution and resources would be helpful as I am stuck at it for hours and can't seem to figure the issue. and store is mobx store if that helps


Solution

  • You using setState in a wrong way.

    setState() enqueues changes to the component state and tells React that this component and its children need to be re-rendered with the updated state. This is the primary method you use to update the user interface in response to event handlers and server responses.

    React docs

    1. So it asynchronous and you can't guarantee when update happens.
    2. Using setTimeout is a bad manners in React.
    3. Storing whole components in state, e.g. locationOptions isn't good idea either.
    4. Better to move input to separate component, as i see only defaultChecked different.
    5. Better to use Hooks, easier to think about this in React way, it's require some time and effort to figure out how to write declarative instead of imperative code.

    Can refactor a litle

    // sync local state and props is a pain, better to avoid it
      //constructor(props) {
       //super(props);
        //const location = this.props.store.selectedLocation
       // this.state = {
          //LocationId: location.LocationId,
        //}
    //}
    
     const location = this.props.store.selectedLocation;
    
    render() {
        return (
            <div>
                <Modal>
                    <Form>
                        <FormGroup>
                            <input
                                value={this.props.store.selectedLocation}
                                type="text"
                                name="Location"
                                id="Location"
                            />
                        </FormGroup>
                        <FormGroup>
                            {this.props.store.cationTypes.map((value) => (
                                <CustomInput
                                    type="checkbox"
                                    id={value.LocationTypeId}
                                    key={value.LocationTypeId}
                                    value={value.LocationTypeId}
                                    defaultChecked={location.LocationTypes.includes(value.LocationTypeId)}
                                    label={`${value.LocationTypeName}`}
                                    className="mb-0"
                                    onChange={this.handleCheckbox.bind(this)}
                                />}
                            ))
                        </FormGroup>
                    </Form>
                </Modal>
            </div>
        );
    }