如何使用 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} />
}
我正在玩钩子,我正在尝试执行以下操作:
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} />
}