【问题标题】:How to focus something on next render with React Hooks如何使用 React Hooks 专注于下一次渲染
【发布时间】:2019-04-18 06:49:39
【问题描述】:

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

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 FAQ 中提出的 usePrevious 钩子,但这似乎是一个痛苦的解决方法。

有什么不同的方法吗?

【问题讨论】:

    标签: reactjs react-hooks


    【解决方案1】:

    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>

    【讨论】:

    • useLayoutEffect 通常首选用于 DOM 相关的突变和检查。
    • 使用 Typescript,如果错误提示为 Object is possibly 'null'.,您必须输入引用 const inputRef = useRef&lt;HTMLInputElement&gt;(null); 并使用条件 if (inputRef.current)
    【解决方案2】:

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

    但作为附加说明,如果您使用的是功能组件,请使用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>
            )
        })
    

    【讨论】:

    • 这如何回答这个问题?
    【解决方案3】:

    或者直接使用这个组件

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

    【讨论】:

    • 为什么是inputRef as any?没有这个演员表不应该正确输入吗?
    • @VincentAUDIBERT 行之有效的东西总比完美的好。你不这么认为吗?
    猜你喜欢
    • 2021-09-09
    • 2021-05-31
    • 1970-01-01
    • 2020-02-23
    • 2020-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多