reactjs JavaScript的.setSelectionRange()与React挂钩不兼容吗?

lnlaulya  于 2022-11-22  发布在  React
关注(0)|答案(1)|浏览(120)

此问题修改了r/reactjs上的question
我有一个受控的input,我可以通过编程改变它的值。我想使用.setSelectionRange()来保持输入中插入符号的位置。
但这行不通:默认情况下,每次重新渲染都会自动将选择范围设置为输入的结尾
此问题在sandbox中说明,其中原始问题的作者使用10 ms setTimeout()延迟修复了此问题。
如何在不使用setTimeout()getSnapshotBeforeUpdate()的情况下实现这一点?setTimeout()getSnapshotBeforeUpdate()与Hooks不兼容。

hrirmatl

hrirmatl1#

在我看来,基本的问题是.setSelectionRange()在模板中被内联使用,应该被 Package 在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});
}

将模板更改为调用handleSelection()

<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
    );
  }}
/>

相关问题