简体   繁体   中英

Input not focusing the first time key is pressed

I want to make an input appear (go from display: none to display: block ) when / is pressed. Then the input should be focused (the cursor should be in the input ).

import React from "react";
import { useState, useEffect, useRef, ChangeEvent } from "react";
import { createRoot } from "react-dom/client";

function App() {
  const [inputValue] = useState("");
  const [isInputFocused, setIsInputFocused] = useState(false);
  const inputRef = useRef<HTMLInputElement | null>(null);

  function handleInputChange(event: ChangeEvent<HTMLInputElement>) {
    // some code
  }

  function handleInputBlur(event: ChangeEvent<HTMLInputElement>) {
    setIsInputFocused(false);
  }

  function handleDocumentKeyDown(event: any) {
    if (event.key === "/") {
      event.preventDefault();
      setIsInputFocused(true);
      inputRef.current?.focus();
    }
  }

  useEffect(() => {
    inputRef.current?.focus();

    document.addEventListener("keydown", handleDocumentKeyDown);

    return () => {
      document.removeEventListener("keydown", handleDocumentKeyDown);
    };
  }, []);

  return (
    <div id="keys" className={isInputFocused ? "active" : "inactive"}>
      <input
        ref={inputRef}
        type="text"
        onChange={handleInputChange}
        onBlur={handleInputBlur}
        value={inputValue}
      />
    </div>
  );
}

const root = createRoot(document.getElementById("root")!);
root.render(<App />);

This works as expected... except the first time you press / , the input appears, but it's not focused (the cursor doesn't jump to the input ). You have to press / again for the input to be focused.

Why is this? And how to change the code so that the input is focused the first time you press / ?

Live example:

编辑 React 输入焦点

As @ghybs said, setting state is async, so the actual re-render will happen at the next tick.

This means you can't immediately expect the input field to be rendered as soon as you set the isInputFocused state to true.

It needs to wait till the next tick.

Easiest way to wait till the next tick in React is using setTimeout :

setIsInputFocused(true);
setTimeout(() => {
  inputRef.current?.focus();
}, 0);

A more elegant solution is to wait for isInputFocused state change and apply the focus action:

useEffect(() => {
  if (isInputFocused) {
    inputRef.current?.focus();
  }
}, [isInputFocused]);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM