这个问题改进了关于r/reactjs的问题。
我有一个受控input
,我可以通过编程方式更改其值。我想使用.setSelectionRange()
来保持输入中的插入符号位置。
除了这不起作用:默认情况下,每次重新渲染都会自动将选择范围设置为输入的末尾。
这个问题在这个沙盒中得到了说明,原始问题的作者用 10 毫秒的setTimeout()
延迟解决了问题。
如何在不使用与 Hooks 不兼容的setTimeout()
或getSnapshotBeforeUpdate()
的情况下实现这一点?
在我看来,基本问题是.setSelectionRange()
在模板中内联使用,应该包装在useEffect()
中。
我也会拉出选择处理程序,只是为了更整洁一点(根据handleDomainChange()
和handleSubmit()
(。
使用选择更新的效果
const[selection, setSelection] = useState()
useEffect(() => {
if (!selection) return; // prevent running on start
const {start, end} = selection;
inputEl.current.focus();
inputEl.current.setSelectionRange(start, end);
}, [selection])
const handleSelection = (e) => {
const start = inputEl.current.selectionStart;
const end = inputEl.current.selectionEnd;
... // other code within selection handler as per original
// inputEl.current.focus();
// // the line below doesn't work!
// // inputEl.current.setSelectionRange(start + e.native.length, end + e.native.length)
// //this one does, but is not good practice..
// setTimeout(
// () =>
// inputEl.current.setSelectionRange(
// start + e.native.length,
// end + e.native.length
// ),
// 10
// );
setSelection({start: start + e.native.length, end: end + e.native.length});
}
模板更改为调用句柄选择((
<Picker
set="emojione"
onSelect={event => {
handleSelection(event)
}}
/>
原始代码供参考
<Picker
set="emojione"
onSelect={e => {
const start = inputEl.current.selectionStart;
const end = inputEl.current.selectionEnd;
//const result = domainString.substring(0, start) + e.native + domainString.substring(end, domainString.length)
setDomainString(
prevString =>
prevString.substring(0, start) +
e.native +
prevString.substring(end, prevString.length)
);
setDomainsArray(
domainEndings.map(
ending =>
domainString.substring(0, start) +
e.native +
domainString.substring(end, domainString.length) +
ending
)
);
inputEl.current.focus();
// the line below doesn't work!
// inputEl.current.setSelectionRange(start + e.native.length, end + e.native.length)
//this one does, but is not good practice..
setTimeout(
() =>
inputEl.current.setSelectionRange(
start + e.native.length,
end + e.native.length
),
10
);
}}
/>