47

我正在玩钩子,我正在尝试执行以下操作:

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,因为组件还没有重新渲染,并且输入字段还没有渲染(因此还不能被聚焦)。

这样做的正确方法是什么?我可以使用usePreviousReact Hooks FAQ 中提出的钩子,但这似乎是一个痛苦的解决方法。

有不同的方法吗?

4

3 回答 3

79

您可以使用钩子在每次渲染更改useEffect后运行函数。isEditing在此功能中,您可以检查是否isEditingtrue并聚焦输入。

例子

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>

于 2018-11-15T08:55:33.397 回答
4

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

但作为附加说明,如果您使用的是功能组件,请使用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>
        )
    })
于 2020-07-04T12:32:00.800 回答
0

或者简单地使用这个组件

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} />
}

于 2021-07-22T14:24:32.747 回答