0
votes

Trying to understand the state update -UseState React hook. setting the message inside onchange event of text area re-renders immediately and able to see the updated message state (handleChangeMessage). But while updating the state inside the on-Keypress event doesn't display the updated message text immediately (handleKeyPressMessage).

Why the handleKeyPressMessage- doesn't render the latest value but handleChangeMessage does? The Irony here is the log statement inside handleKeyPress executes first before the onchange event.

code-sandbox link: https://codesandbox.io/s/usestate-01-forked-lvyio?file=/src/index.js

import React, { useState } from "react";
import ReactDOM from "react-dom";

import "./styles.css";

const Message = () => {
  const [handleChangeMessage, setHandleChangeMessage] = useState("");
  const [sendButtonClass, setSendButtonClass] = useState("send-disabled");
  const [handleKeyPressMessage, setHandleKeyPressMessage] = useState("");

  const handlechange = (e) => {
    console.log("change");
    setHandleChangeMessage(e.target.value);
  };

  const handleKeyPress = (e) => {
    console.log("key");
    setHandleKeyPressMessage(e.target.value);
    if (handleChangeMessage == "") {
      setSendButtonClass("send-disabled");
    } else {
      setSendButtonClass("send");
    }
  };
  return (
    <div>
      <input
        type="text"
        value={handleChangeMessage}
        placeholder="Enter a message"
        onChange={handlechange}
        onKeyPress={handleKeyPress}
      />
      <button className={sendButtonClass}>Send</button>
      <p>
        "message updated via onChange event ======> : "
        <strong>{handleChangeMessage}</strong>
        <br />
        "message updated via onKeyPress event =====> : "
        <strong>{handleKeyPressMessage}</strong>
      </p>
    </div>
  );
};

const rootElement = document.getElementById("root");
ReactDOM.render(<Message />, rootElement);

UPDATE

The issue here is keypress event is triggered first before onchange event(updates handleChangemessage). So the input element has the outdated value in HandleKeyPress event(e.target.value i.e handleChangemessage) Changing the keypress event to keyup will resolve the issue as Abhishek suggested

3

3 Answers

0
votes

In Place of

onKeyPress={handleKeyPress}

Use

onKeyUp={handleKeyPress}
0
votes

First of all, it might not be a good thing that should be assumed in the implementation level to rely on. similar to following post

keypress fires before on-change and doesn't have access to a new value which is going to be bound to the input element.

  1. change event triggers event handler handlechange
  2. update state (handlechange) asynchronously
  3. bind new value handlechange to the input element and cause re-render.

but you can access the key property on the event to get the last pressed key and contacting that to the previous keyPress state

const handleKeyPress = (e) => {
  console.log("key"); // to see the input value in this stage e.target.value
  setHandleKeyPressMessage(e.target.value + e.key);
};
0
votes

event.target returns the element that triggered event. Since the event is triggered by user pressing the key, there is no such element. You should check if your e.target.value returns undefined. If it does, then obtain the value from your input field by giving it unique ID, using something like:

const handleKeyPress = (e) => { console.log("key"); setHandleKeyPressMessage(document.getElementById("your-input-id").value); };