Как сфокусировать внимание на следующем рендере с помощью React Hooks

Я играю с крючками и пытаюсь сделать следующее:

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

const EditableField = () => {
  const [isEditing, setEditing] = useState(false);
  const inputRef = useRef();
  const toggleEditing = () => {
    setEditing(!isEditing);
    if (isEditing) {
      inputRef.current.focus();
    }
  };
  return (
    <>
      {isExpanded && <input ref={inputRef} />}
      <button onClick={toggleEditing}>Edit</button>
    </>
  );
};

Это потерпит неудачу, потому что current имеет значение null, поскольку компонент еще не перерисован, а поле ввода еще не визуализировано (и поэтому не может быть сфокусировано).

Как правильно это сделать? Я могу использовать ловушку usePrevious, предложенную в FAQ по React Hooks, но это похоже на болезненный обходной путь.

Есть ли другой способ?

Ответ 1

Вы можете использовать ловушку useEffect, чтобы запускать функцию после каждого рендера, когда изменяется isEditing. В этой функции вы можете проверить, является ли isEditing true, и сфокусировать вход.

Пример

const { useState, useRef, useEffect } = React;

const EditableField = () => {
  const [isEditing, setEditing] = useState(false);
  const toggleEditing = () => {
    setEditing(!isEditing);
  };

  const inputRef = useRef(null);

  useEffect(() => {
    if (isEditing) {
      inputRef.current.focus();
    }
  }, [isEditing]);
  
  return (
    <div>
      {isEditing && <input ref={inputRef} />}
      <button onClick={toggleEditing}>Edit</button>
    </div>
  );
};

ReactDOM.render(<EditableField />, document.getElementById("root"));
<script src="https://unpkg.com/[email protected]/umd/react.production.min.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.production.min.js"></script>
  
<div id="root"></div>