skip to Main Content

I have a component where users can enter text into an input field

import { useState } from "react";

export function App() {
    const [txt, setTxt] = useState("");

    return (
        <input value={txt} onInput={(e) => { setTxt(() => e.currentTarget.value); }} />
    );
}

Expected behaviour:

The input field should display the value of txt. Whenever the user types the onInput event should trigger and update the value of txt.

Actual behaviour

The code crashes after triggering the onInput event for the second time. I get errors like

Uncaught TypeError: Cannot read properties of null (reading 'value')
    at <anonymous>:41:36
    at basicStateReducer (<anonymous>:12325:51)
    at updateReducer (<anonymous>:12418:32)
    at updateState (<anonymous>:12654:20)
    at Object.useState (<anonymous>:13444:26)
    at useState (<anonymous>:1114:31)
    at App (<anonymous>:37:51)
    at renderWithHooks (<anonymous>:12163:28)
    at updateFunctionComponent (<anonymous>:15206:30)
    at beginWork (<anonymous>:16602:24)

and

The above error occurred in the <App> component:

    at App (<anonymous>:37:51)

Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries.

What is wrong with the code?

4

Answers


  1. Solution:

    onInput={(e) => {
      setTxt(e.currentTarget.value);
    }}
    

    Explanation:

    Arrow functions lexically bind the this value, meaning they inherit the this value from their surrounding scope.

    In the scenario where you are using setTxt(() => e.currentTarget.value), the arrow function () => e.currentTarget.value captures the e object from the surrounding scope, which is the onchange event handler, but it does not capture the value of e.target.value at the moment when the onChange event was triggered hence, it gets e.target as undefined.

    Login or Signup to reply.
  2. You should use onChange listner instead of onInput

    import { useState } from "react";
    
    export function App() {
      const [txt, setTxt] = useState("");
    
      return (
        <input
          value={txt}
          onChange={(e)=> setTxt(e.currentTarget.value)}
        />
      );
    }
    
    Login or Signup to reply.
  3. You can use this code and it will work fine. Here I have used setTxt(e.currentTarget.value) instead of setTxt(() => e.currentTarget.value);. Rest of the code is unchanged.

    import React, { useState } from "react";
    
    export default function App() {
      const [txt, setTxt] = useState("");
    
      return (
        <input
          value={txt}
          onInput={(e) => {
            console.log("e.currentTarget.value", e.currentTarget.value);
            setTxt(e.currentTarget.value);
          }}
        />
      );
    }
    
    Login or Signup to reply.
  4. you are using an unnecessary callback inside your input.
    try to replace this:

    <input value={txt} onInput={(e) => { setTxt(() => e.currentTarget.value); }} />
    

    to this:

    <input value={txt} onInput={(e) => { setTxt(e.currentTarget.value); }} />
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search