reectrix
reectrix

Reputation: 8619

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

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?

Upvotes: 78

Views: 58193

Answers (7)

gajuki
gajuki

Reputation: 1

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
     });
}

Upvotes: 0

Gaurav Sharma
Gaurav Sharma

Reputation: 161

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>
    )
}

Upvotes: 9

writer_chris
writer_chris

Reputation: 156

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) }}
    />
);
};

Upvotes: 7

Filat Astakhov
Filat Astakhov

Reputation: 1

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.

Upvotes: -2

Aman
Aman

Reputation: 339

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);
   }

Upvotes: 10

Taohidul Islam
Taohidul Islam

Reputation: 5414

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.

Upvotes: 2

Michelle Tilley
Michelle Tilley

Reputation: 159095

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.

Upvotes: 71

Related Questions