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?
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.
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.
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.
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.
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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With