如何使用 React Hooks 专注于下一次渲染

How to focus something on next render with 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 为空,因为组件尚未重新呈现,并且输入字段尚未呈现(因此还无法聚焦)。

正确的做法是什么?我可以使用 React Hooks 常见问题解答中提出的 usePrevious 钩子,但这似乎是一个痛苦的解决方法。

还有其他方法吗?

isEditing 更改时,您可以在每次渲染后使用 useEffect 挂钩 运行 函数。在此函数中,您可以检查 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/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>

我知道接受的答案涵盖了上述问题中的请求元素。

但作为附加说明,如果您使用的是功能组件,请使用 React.forwardRef 将引用传递给子组件。有可能 对于以后提到这个问题的人绝对有用。

以更简洁的方式,您可以编写接受 ref 的子组件,如下所示:

    const InputField = React.forwardRef((props, ref) => {
        return (
            <div className={props.wrapperClassName}>
                <input 
                   type={props.type}
                   placeholder={props.placeholder} 
                   className={props.className}
                   name={props.name}
                   id={props.id}
                   ref={ref}/>
            </div>
        )
    })

或者简单地使用这个组件

import { FC, useEffect, useRef } from 'react'

export const FocusedInput: FC<JSX.IntrinsicElements['input']> = (props) => {

    const inputRef = useRef<null | HTMLElement>(null)
    useEffect(() => {
        inputRef.current!.focus()
    }, [])
    return <input {...props} type="text" ref={inputRef as any} />
}