React点击按钮修改输入框值后选中文本需点击两次如何解决?
问题原因
React中setState是异步批量更新的,调用setName('ray')后不会立刻更新state和对应的DOM节点,当前同步代码中的inputRef.current.select()执行时,输入框的value还停留在更新前的值,所以第一次点击没有选中效果。等本轮同步任务执行完成后React才会触发重渲染更新输入框内容,第二次点击时输入框内容已经是更新后的值,才会正常触发选中文本的逻辑。
方案1:使用useEffect监听状态变化,在DOM更新后执行选中逻辑
把选中文本的逻辑绑定到name状态的更新后生命周期,保证每次name更新完成、DOM同步后再执行选中,该方案不会打断React默认的批量更新逻辑,适用范围更广,更推荐使用:
import { useRef, useState, useEffect } from "react"; import "./styles.css"; export default function App() { const [name, setName] = useState('') const inputRef = useRef(); // 新增useEffect监听name变化 useEffect(() => { if(name) { // 可自定义判断条件避免不必要的选中触发 inputRef.current.select(); } }, [name]) const editItem = () => { setName('ray') }; return ( <> <input ref={inputRef} type="text" value={name} placeholder="e.g. eggs" onChange={(e)=>setName(e.target.value)} /> <button type="button" className="edit-btn" onClick={editItem}> Focus </button> </> ); }
方案2:使用flushSync强制同步刷新状态更新
如果不想额外新增useEffect监听,可以用ReactDOM提供的flushSync强制让状态更新立刻同步刷新DOM,再执行选中逻辑:
import { useRef, useState } from "react"; import { flushSync } from 'react-dom'; import "./styles.css"; export default function App() { const [name, setName] = useState('') const inputRef = useRef(); const editItem = () => { // 用flushSync包裹状态更新,强制同步刷新 flushSync(() => { setName('ray') }) inputRef.current.select(); }; return ( <> <input ref={inputRef} type="text" value={name} placeholder="e.g. eggs" onChange={(e)=>setName(e.target.value)} /> <button type="button" className="edit-btn" onClick={editItem}> Focus </button> </> ); }
内容的提问来源于stack exchange,提问作者Ruchi Ray
相关产品推荐
相关产品推荐

