需向父组件透传ref时,React子组件如何判断输入框是否获焦?
解决React子组件判断输入框焦点状态的问题
你可以通过两种方式实现需求,既兼容父组件传入的可选inputRef,又能在子组件内跟踪输入框的焦点状态:
方案一:用状态直接跟踪焦点(推荐,无需额外ref)
通过onFocus和onBlur事件更新子组件内部状态,同时保留父组件传入的事件回调:
import React, { useState, FocusEventHandler } from "react"; import { RefCallBack } from "react-hook-form"; interface IInput { inputRef?: RefCallBack; onFocus?: FocusEventHandler<HTMLInputElement>; onBlur?: FocusEventHandler<HTMLInputElement>; } const Input: React.FC<IInput> = ({ inputRef, onFocus, onBlur }) => { // 内部状态跟踪焦点状态 const [isFocused, setIsFocused] = useState(false); const handleFocus: FocusEventHandler<HTMLInputElement> = (e) => { setIsFocused(true); // 调用父组件传入的onFocus回调(如果存在) onFocus?.(e); }; const handleBlur: FocusEventHandler<HTMLInputElement> = (e) => { setIsFocused(false); // 调用父组件传入的onBlur回调(如果存在) onBlur?.(e); }; return ( <div className={isFocused ? "input-container-focused" : ""}> <input type="text" ref={inputRef} onFocus={handleFocus} onBlur={handleBlur} /> </div> ); }; export default Input;
你可以直接用isFocused状态控制样式,比如给外层容器添加聚焦专属类名。
方案二:合并内部ref与父组件传入的ref
如果需要直接通过DOM元素判断焦点(比如检查document.activeElement),可以创建内部ref,并将其与父组件的inputRef合并:
import React, { useRef, useState, FocusEventHandler } from "react"; import { RefCallBack } from "react-hook-form"; interface IInput { inputRef?: RefCallBack; onFocus?: FocusEventHandler<HTMLInputElement>; onBlur?: FocusEventHandler<HTMLInputElement>; } const Input: React.FC<IInput> = ({ inputRef, onFocus, onBlur }) => { const internalRef = useRef<HTMLInputElement>(null); const [isFocused, setIsFocused] = useState(false); // 合并ref回调:同时传递元素给内部ref和父组件的inputRef const mergedRef = (element: HTMLInputElement | null) => { internalRef.current = element; inputRef?.(element); }; const handleFocus: FocusEventHandler<HTMLInputElement> = (e) => { setIsFocused(true); onFocus?.(e); }; const handleBlur: FocusEventHandler<HTMLInputElement> = (e) => { setIsFocused(false); onBlur?.(e); }; // 额外监听全局焦点变化,处理输入框被外部元素夺走焦点的场景 React.useEffect(() => { const checkFocus = () => { setIsFocused(document.activeElement === internalRef.current); }; window.addEventListener("focus", checkFocus, true); window.addEventListener("blur", checkFocus, true); return () => { window.removeEventListener("focus", checkFocus, true); window.removeEventListener("blur", checkFocus, true); }; }, []); return ( <div className={isFocused ? "input-container-focused" : ""}> <input type="text" ref={mergedRef} onFocus={handleFocus} onBlur={handleBlur} /> </div> ); }; export default Input;
这个方案通过合并ref,既不影响父组件对输入框的引用,又能在子组件内拿到DOM元素,结合全局焦点事件确保状态准确。
内容的提问来源于stack exchange,提问作者M S
相关产品推荐
相关产品推荐

