Skip to content Skip to sidebar Skip to footer

OnChange Event Updates State With 1 Character Delay

I have my input component set up in the following way constructor(props) { super(props) this.state = {text: ''} } componentWillReceiveProps(props) { if(props.val

Solution 1:

What helped me in this case was finding out that setState has a callback function, i.e

this.setState({ someState: 'someState' }, () => {
  //Anything you need to do after state update here
});

Solution 2:

What you want to do is check if state needs changing in componentWillReceiveProps. This is from https://github.com/calitek/ReactPatterns React.14.Common/FormInputs.

import React from 'react';

class JInputRender extends React.Component {
   render() {
    let inputSty = this.props.input.style ? this.props.input.style : {color: 'red'};
    let textValue = this.state.textValue;
    let colorValue = this.props.input.colorValue ? this.props.input.colorValue : '#1A3212';
    let checkedValue = (this.props.input.checkedValue != null) ? this.props.input.checkedValue : false;
    let numberValue = this.props.input.numberValue ? this.props.input.numberValue : 0;
    let radioValue = this.props.input.radioValue ? this.props.input.radioValue : '';
    let radioChecked = (this.props.input.radioChecked != null) ? this.props.input.radioChecked : false;
    let min = this.props.input.min ? this.props.input.min : 0;
    let max = this.props.input.max ? this.props.input.max : 100;
    let step = this.props.input.step ? this.props.input.step : 1;
    let inputType = this.props.input.type ? this.props.input.type : 'text';

    let returnRadio = (
        <input
          ref="inputRef"
          type={inputType}
          style={inputSty}
          checked={radioChecked}
          value={radioValue}
          onChange={this.handleValueChange} />
      )

    let returnChecked = (
        <input
          ref="inputRef"
          type={inputType}
          style={inputSty}
          checked={checkedValue}
          onChange={this.handleCheckedChange} />
      )

    let returnColor = (
        <input
          type={inputType}
          ref="inputRef"
          style={inputSty}
          value={colorValue}
          onChange={this.handleValueChange} />
      )

    let returnNumber = (
        <input
          type={inputType}
          ref="inputRef"
          style={inputSty}
          value={numberValue}
          min={min} max={max} step={step}
          onChange={this.handleValueChange} />
      )

    let returnText = (
        <input
          type={inputType}
          ref="inputRef"
          style={inputSty}
          value={textValue}
          onChange={this.handleTextValueChange} />
      )

    let returnFile = (
        <input
          type={inputType}
          ref="inputRef"
          style={inputSty}
          onChange={this.handleFolderChange}
          multiple />
      )

    let returnIt = {};
    switch (inputType) {
      case 'checkbox': returnIt = returnChecked; break;
      case 'radio': returnIt = returnRadio; break;
      case 'color': returnIt = returnColor; break;
      case 'number':
      case 'range': returnIt = returnNumber; break;
      case 'file': returnIt = returnFile; break;
      default: returnIt = returnText; break;
    }

    return (returnIt);
  }
}

export default class JInput extends JInputRender {
  constructor(props) {
    super();
    this.state = {textValue: ''};
  }

  componentDidMount = () => {
    if (this.props.input.textValue) this.setState({textValue: this.props.input.textValue});
    if (this.props.input.focus) this.refs.inputRef.focus();
  };
  componentWillReceiveProps = (nextProps) => {
    if (nextProps.input.textValue && (this.state.textValue != nextProps.input.textValue))
      {this.setState({textValue: nextProps.input.textValue});}
  };

  handleCheckedChange = (event) => { this.props.handleChange(this.props.input.name, event.target.checked); };
  handleTextValueChange = (event) => {
    let newValue = event.target.value;
    this.setState({textValue: newValue});
    this.props.handleChange(this.props.input.name, newValue);
  };
  handleValueChange = (event) => { this.props.handleChange(this.props.input.name, event.target.value); };
  handleFolderChange = (event) => { this.props.handleChange(this.props.input.name, event.target.value); };
}

This is the calling component.

import React from 'react';

import Actions from './../flux/Actions';
import JInput from './common/jInput';

import BasicStore from './../flux/Basic.Store';

let AppCtrlSty = {
  height: '100%',
  padding: '0 10px 0 0'
}

let checkBoxSty = {
  boxSizing: 'border-box',
  display: 'inline-block',
  lineHeight: '18px',
  marginLeft: '2px',
  outline: 'none',
  position: 'relative'
};

let radioSty = {color: "blue"}

let input3Sty = {color: 'green'};

let inputLabel = {margin: '0 5px'};

let textInput1 = {name: 'text', type: 'text', textValue: '', focus: true};
let checkInput1 = {name: 'checkbox', type: 'checkbox', style: checkBoxSty};
let colorInput = {name: 'color', type: 'color'};
let fileInput = {name: 'folder', type: 'file'};
let numberInput = {name: 'number', type: 'number', min: 0, max: 100};
let rangeInput = {name: 'range', type: 'range', min: 0, max: 100};

let radioInput1 = {name: 'radioGroup', type: 'radio', radioValue: 'set'};
let radioInput2 = {name: 'radioGroup', type: 'radio', radioValue: 'setkey'};
let radioInput3 = {name: 'radioGroup', type: 'radio', radioValue: 'key'};

class AppCtrlRender extends React.Component {
   render() {
     let inputData = this.state.data;

    textInput1.textValue = inputData.text;
    checkInput1.checkedValue = inputData.checkbox;
    colorInput.colorValue = inputData.color;
    numberInput.numberValue = inputData.number;
    rangeInput.numberValue = inputData.range;
    fileInput.folderValue = inputData.folder;

    let currentRadioGroupValue = this.state.data.radioGroup;
    radioInput1.radioChecked = (currentRadioGroupValue == radioInput1.radioValue);
    radioInput2.radioChecked = (currentRadioGroupValue == radioInput2.radioValue);
    radioInput3.radioChecked = (currentRadioGroupValue == radioInput3.radioValue);

    let selected = inputData.checkbox ? 'true' : 'false';
    let radioGroupName1 = 'key1'; //must be distinct for each use of JRadioGroup
    let radioValue = inputData.radioGroup;
    return (
      <div id='AppCtrlSty' style={AppCtrlSty}>
        React 0.14 Form input<br/><br/>
        Text: <JInput input={textInput1} handleChange={this.handleValueChange} /><br/><br/>
        Checkbox: <JInput input={checkInput1} handleChange={this.handleValueChange} /> Value: {selected}<br/><br/>
        Color: <JInput input={colorInput} handleChange={this.handleValueChange} /> Value: {colorInput.colorValue}<br/><br/>
        File: <JInput input={fileInput} handleChange={this.handleValueChange} /> Value: {fileInput.folderValue}<br/><br/>
        Number: <JInput input={numberInput} handleChange={this.handleValueChange} /> Value: {numberInput.numberValue}<br/><br/>
        Range: <JInput input={rangeInput} handleChange={this.handleValueChange} /> Value: {rangeInput.numberValue}<br/><br/>

        Radio Input: &nbsp;
        <JInput input={radioInput1} handleChange={this.handleValueChange} />&nbsp;Set &nbsp;
        <JInput input={radioInput2} handleChange={this.handleValueChange} />&nbsp;Set/Key &nbsp;
        <JInput input={radioInput3} handleChange={this.handleValueChange} />&nbsp;Key &nbsp;
        Value: {radioValue}
      </div>
    );
  }
}

function getState() { return {data: BasicStore.getData()}; };

export default class AppCtrl extends AppCtrlRender {
  constructor() {
    super();
    this.state = getState();
  }

  componentDidMount() { this.unsubscribe = BasicStore.listen(this.storeDidChange); };
  componentWillUnmount() { this.unsubscribe(); };

  storeDidChange = () => { this.setState(getState()); };
  handleValueChange = (name, value) => { Actions.editRecord(name, value); };
}

Solution 3:

You can you another auxiliary variable to store and use the value immediately.

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

  componentWillReceiveProps(props) {
    if(props.value) {
      this.setState({text: props.value});
      this.text = props.value;
    }
  }

  handleChange(event) {
    event.persist();
    this.setState({text: event.target.value});
    this.text = event.target.value;
    if(typeof(this.props.onChange) === 'function') {
      this.props.onChange(event);
    }
  }

  render() {
    return (
      <input
        onChange={ this.handleChange.bind(this) }
        value={ this.state.text }
        type="text"
        placeholder={ this.props.placeholder }
        className={ `form-text-input ${this.props.helpers}` }/>
    );
  }


//Handle change
    handleChange(event) {
      this.text = event.target.value;
      this.setState({text: event.target.value})
      console.log(this.state.text);
    }

    <TextInput
      helpers="transparent seperator-text"
      value={this.state.text}
      onChange={this.handleChange.bind(this)} />

But always you should use this.state.text variable to show text in your UI.


Post a Comment for "OnChange Event Updates State With 1 Character Delay"