依赖更新后useCallback钩子未触发,如何实现过渡结束后输入框聚焦?
问题原因
React的回调ref仅在组件挂载、卸载或ref属性本身的引用发生变化时才会触发。你用useCallback包裹了ref回调并依赖transitionEnded,虽然当transitionEnded从false变为true时,useCallback会返回一个新的函数引用,但此时TextInput已经完成挂载,React不会主动重新执行这个回调,导致你的聚焦逻辑无法触发。
解决方案
推荐使用**useRef存储DOM元素 + useEffect监听状态变化**的方式,这种方案更简洁直接,避免回调ref的触发时机限制。
代码实现
import { useState, useRef, useEffect } from 'react'; // ...其他业务代码 const [transitionEnded, setTransitionEnded] = useState(false); const inputRef = useRef(null); // 用useRef直接存储输入框DOM元素 // 监听transitionEnded状态变化,触发聚焦逻辑 useEffect(() => { // 确保状态已切换且DOM元素存在 if (transitionEnded && inputRef.current) { if (shouldDelayFocus) { setTimeout(() => { focusAndUpdateMultilineInputRange(inputRef.current); }, CONST.ANIMATED_TRANSITION); } else { focusAndUpdateMultilineInputRange(inputRef.current); } } }, [transitionEnded, shouldDelayFocus]); // 组件渲染部分 <ScreenWrapper onEntryTransitionEnd={() => { console.log("transition ended"); setTransitionEnded(true); }} > <TextInput ref={inputRef} /> </ScreenWrapper>
方案说明
- 用
useRef直接绑定到TextInput的ref属性,可随时获取输入框的DOM元素,不受组件生命周期或状态变化限制。 - 通过
useEffect监听transitionEnded的变化,一旦状态变为true且DOM元素存在,立即执行聚焦逻辑。 - 将
shouldDelayFocus加入useEffect的依赖数组,确保延迟逻辑的正确性。
备选方案(若坚持使用回调ref)
如果一定要保留回调ref的写法,可以通过额外状态存储DOM元素,再结合useEffect触发聚焦:
const [transitionEnded, setTransitionEnded] = useState(false); const inputRef = useRef(null); const [inputElement, setInputElement] = useState(null); const inputRefCallback = useCallback((el) => { setInputElement(el); inputRef.current = el; }, []); useEffect(() => { if (transitionEnded && inputElement) { if (shouldDelayFocus) { setTimeout(() => { focusAndUpdateMultilineInputRange(inputElement); }, CONST.ANIMATED_TRANSITION); } else { focusAndUpdateMultilineInputRange(inputElement); } } }, [transitionEnded, inputElement, shouldDelayFocus]); // 组件部分 <ScreenWrapper onEntryTransitionEnd={() => setTransitionEnded(true)} > <TextInput ref={inputRefCallback} /> </ScreenWrapper>
内容的提问来源于stack exchange,提问作者Chirag Arora
相关产品推荐
相关产品推荐

