onChange in React doesn't capture the last character of text

JavascriptReactjs

Javascript Problem Overview


This is my render function:

  render: function() {
    return  <div className="input-group search-box">
              <input
                onChange={this.handleTextChange}
                type="text"
                value={this.state.text}
                className="form-control search-item" />
              <span className="input-group-btn"></span>
        </div>
   }

and I have this as my event handler:

   handleTextChange: function(event) {
     console.log(event.target.value);
     this.setState({
       text: event.target.value
     });
   }

The problem is that when I "save" an item, or console.log print the output, the last character is missing - for instance, if I enter "first", I'll get "firs" printed out, and there needs to be another key event to capture the last character. I've tried onKeyUp - which doesn't let me type anything in, and I've also tried onKeyDown and onKeyPress, which output nothing. What is happening here and why? and how can I get that last character to show up?

Javascript Solutions


Solution 1 - Javascript

When are you logging the state? Remember that setState is asynchronous, so if you want to print the new state, you have to use the callback parameter. Imagine this component:

let Comp = React.createClass({
  getInitialState() {
    return { text: "abc" };
  },

  render() {
    return (
      <div>
        <input type="text" value={this.state.text}
               onChange={this.handleChange} />
        <button onClick={this.printValue}>Print Value</button>
      </div>
    );
  },

  handleChange(event) {
    console.log("Value from event:", event.target.value);

    this.setState({
      text: event.target.value
    }, () => {
      console.log("New state in ASYNC callback:", this.state.text);
    });

    console.log("New state DIRECTLY after setState:", this.state.text);
  },

  printValue() {
    console.log("Current value:", this.state.text);
  }
});

Typing a d at the end of the input will result in the following being logged to the console:

Value from event: abcd
New state DIRECTLY after setState: abc
New state in ASYNC callback: abcd

Notice that the middle value is missing the last character. Here's a working example.

Solution 2 - Javascript

Since setState() function in asynchronous, I used await.I achieved this using async and await, here is my code

render: function() {
    return  <div className="input-group search-box">
              <input
                onChange={(e) => {this.handleTextChange(e)}}
                type="text"
                value={this.state.text}
                className="form-control search-item" />
              <span className="input-group-btn"></span>
        </div>
   }

The handleTextCahnge function:

handleTextChange = async function(event) {
     
     await this.setState({text: event.target.value});
     console.log(this.state.text);
   }

Solution 3 - Javascript

Since React v.16.8 react hooks can be helpful. I would recommend useState AND useEffect. The Example is in React Native, however it should show how to work with the useEffect. More information about useEffect: https://reactjs.org/docs/hooks-effect.html

import React, {useState, useEffect} from 'react';
import { TextInput } from 'react-native';

export interface Props{}
 
const InformationInputs: React.FC<Props> = (props) => {
  const [textInputs, setTextInputs] = useState("");

  const handleValueChange = () => {
    console.log(textInputs);
  }

  useEffect(() => {
    handleValueChange();
  }, [textInputs]);

return (
    <TextInput
    placeholder={'Text'}
    onChangeText={(value: string) => { setTextInputs(value) }}
    />
);
};

Solution 4 - Javascript

setState() function in asynchronous. Without using callback you can use another auxiliary variable to store and use the updated value immediately. Like :

export default class My_class extends Component{
constructor(props)
{
super(props):
this.state={
text:"",
};
this.text="";
}
 render: function() {
    return  <div className="input-group search-box">
              <input
                onChange={this.handleTextChange}
                type="text"
                value={this.state.text}
                className="form-control search-item" />
              <span className="input-group-btn"></span>
        </div>
   }

handleTextChange: function(event) {
     console.log(event.target.value);
     this.text = event.target.value;
     this.setState({
      text: event.target.value
     });
   }

You will get your updated value in this.text variable immediately. But you should use this.state.text to show text in your UI.

Solution 5 - Javascript

import React, { useState, useEffect } from 'react';

const MyComponent = () => {

    const [userInput, setUserInput] = useState("");

    const changeHandler = (e) => {
        setUserInput(e.target.value);
    }

    useEffect(()=> {
        //here you will have correct value in userInput 
    },[userInput])

    return (
        <div>
             <input onChange={changeHandler} value={userInput}></input>
        </div>
    )
}

Solution 6 - Javascript

You are printing to the console before setting the state. Write your console log after the state is set. It will show the full text. (I had the same problem)

handleTextChange: function(event) {
     **console.log(event.target.value)**


     this.setState({
         text: event.target.value
     });
}

Solution 7 - Javascript

Since React v. 16.8 you can use react hooks.

import React, { useState } from 'react';

const MyComponent = () => {
    
    const [userInput, setUserInput] = useState("");
            
    const changeHandler = (e) => {
        setUserInput(e.target.value);
    }
        
    return (
        <div>
             <input onChange={changeHandler} value={userInput}></input>
        </div>
    )
}

It works great for me.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionreectrixView Question on Stackoverflow
Solution 1 - JavascriptMichelle TilleyView Answer on Stackoverflow
Solution 2 - JavascriptAmanView Answer on Stackoverflow
Solution 3 - Javascriptwriter_chrisView Answer on Stackoverflow
Solution 4 - JavascriptTaohidul IslamView Answer on Stackoverflow
Solution 5 - JavascriptGaurav SharmaView Answer on Stackoverflow
Solution 6 - JavascriptgajukiView Answer on Stackoverflow
Solution 7 - JavascriptFilat AstakhovView Answer on Stackoverflow