Является ли JavaScript .setSelectionRange () несовместимым с React Hooks? - PullRequest
0 голосов
/ 08 февраля 2020

Этот вопрос обновляет вопрос на r / reactjs.

У меня есть контролируемый input, из которого я могу программно изменить значение. Я хотел бы использовать .setSelectionRange(), чтобы сохранить позицию каретки внутри ввода.

За исключением того, что это не работает: каждый повторный рендеринг автоматически устанавливает диапазон выбора до конца ввода по умолчанию .

Проблема проиллюстрирована в этой песочнице , где автор исходного вопроса исправил проблему с задержкой 10 мс setTimeout().

Как мне добиться этого без использования setTimeout() или getSnapshotBeforeUpdate(), что несовместимо с крючками?

1 Ответ

1 голос
/ 08 февраля 2020

Основная проблема c, как я вижу, заключается в том, что .setSelectionRange() используется в шаблоне in-line и должно быть заключено в useEffect().

Я бы также вытащил обработчик выбора, чтобы быть немного более аккуратным (согласно handleDomainChange() и handleSubmit()).

useEffect для обновления выбора

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
    );
  }}
/>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...