reactjsreact-hooks

How to focus something on next render with React Hooks


I'm playing with hooks, and I'm trying to do the following:

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 (
    <>
      {isEditing && <input ref={inputRef} />}
      <button onClick={toggleEditing}>Edit</button>
    </>
  );
};

This is going to fail, because current is null, since the component haven't re-rendered yet, and the input field is not yet rendered (and therefore can't be focused yet).

What is the right way to do this? I can use the usePrevious hook proposed in the React Hooks FAQ, but it seems like a painful workaround.

Is there a different way?


Solution

  • You can use the useEffect hook to run a function after every render when isEditing changed. In this function you can check if isEditing is true and focus the input.

    Example

    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/react@16.7.0-alpha.2/umd/react.production.min.js"></script>
    <script src="https://unpkg.com/react-dom@16.7.0-alpha.2/umd/react-dom.production.min.js"></script>
      
    <div id="root"></div>