Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 (     <>       {isExpanded && <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?

like image 700
Kris Selbekk Avatar asked Nov 15 '18 08:11

Kris Selbekk


People also ask

How do you focus on next input in React?

To focus on the next field when pressing enter in React, we can set the onKeyDown prop of the inputs to a function that gets the next input and call focus on it. We have the handleEnter function that checks if the pressed key is Enter by checking the event. key property.

How do you autoFocus with React Hooks?

To autofocus the first input element in the form after render, we use useEffect() hook and call the focus() method inside the hook. The dependency array should be an empty array to prevent multiple calls of focus() method on re-render.

Can you nest React Hooks?

React relies on the order in which Hooks are called The rules of React Hooks clearly state: Don't call Hooks inside loops, conditions, or nested functions. Instead, always use Hooks at the top level of your React function. React Hooks need to be called in the same order each time the component renders.

How do you trigger a useEffect on every render?

Passing no 2nd argument causes the useEffect to run every render. Then, when it runs, it fetches the data and updates the state. Then, once the state is updated, the component re-renders, which triggers the useEffect again.


1 Answers

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/[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>
like image 183
Tholle Avatar answered Sep 23 '22 00:09

Tholle