Проблемы при обновлении состояния в React

Пожалуйста, просмотрите мою скрипту js, где я проиллюстрировал проблему.

Вот моя скрипта js: https://jsfiddle.net/jajabya/fb93f7b0/

Моя цель - получить тег input, в котором специальные слова (например, даты или имена пользователей) можно было бы выделить, обернув тегами span.

Должна быть проблема с div, потому что когда я использую поле ввода, все работает нормально.

Моя проблема в том, что я не могу заставить каретку появляться в нужном месте каждый раз, когда состояние обновляется в onInput

  onInput(event) {
    this.setState({
        html: event.target.innerText.toUpperCase()  
    });

  }

каретка возвращается к началу


person Le garcon    schedule 20.11.2017    source источник
comment
Просто быстрый вопрос, почему вы хотите сделать это в элементе div?   -  person Mario Nikolaus    schedule 20.11.2017
comment
Почему вы используете тег div вместо тега input?   -  person Mikhail Katrin    schedule 20.11.2017
comment
потому что в теге input у меня не может быть других тегов html. Я хочу, чтобы специальные слова были заключены в тег span с атрибутом class.   -  person Le garcon    schedule 20.11.2017
comment
Но вы можете обернуть тег input и другие теги в div   -  person Mikhail Katrin    schedule 20.11.2017
comment
Я не очень хорошо тебя понимаю. Моя идея заключается в том, что если пользователь напишет в этом поле, что я хочу пойти туда сегодня, слово сегодня будет выделено. Если бы вы могли привести мне пример или хотя бы подсказать, как этого добиться, я был бы признателен за это @MikhailKatrin   -  person Le garcon    schedule 20.11.2017
comment
Я не понял, чего именно ты хочешь, теперь я вижу   -  person Mikhail Katrin    schedule 20.11.2017
comment
Загляните на draftjs.org, если у вас возникнут трудности при работе с разделом contentEditable. Простой и понятный API.   -  person Nandu Kalidindi    schedule 20.11.2017


Ответы (1)


Моя идея состоит в том, чтобы сохранить текущую позицию каретки в состоянии и установить ее обратно с помощью ссылки в componentDidUpdate() (поскольку ref не перерисовывает компонент).

Примечание. Это прототип идеи, которую я никогда не тестировал в бою, поэтому используйте ее с осторожностью.

Код позиции курсора был взят из этих ответов:

  1. Код для получения позиции курсора

  2. Код для установки позиции курсора

class Editable extends React.Component {
  componentDidUpdate(prev) {
    const { position } = this.props;
  
    if(position !== prev.position && this.ce.childNodes.length) {
      const range = document.createRange();
      const sel = window.getSelection();
      range.setStart(this.ce.childNodes[0], position);
      range.collapse(true);
      sel.removeAllRanges();
      sel.addRange(range);
    }
  }
  
  render() {
    return (
      <div
        contentEditable
        className={this.props.className}
        onInput={this.props.onInput}
        ref={ce => this.ce = ce}
        suppressContentEditableWarning>
        {this.props.html}
      </div>
    );
  }
}

class App extends React.Component {
  state = {
    html: 'Text',
    caret: 0
  };

  handleInput = (event) => this.setState({
    html: event.target.innerText.toUpperCase(),
    position: window.getSelection().getRangeAt(0).startOffset
  });
  
  render() {
    return (
     <Editable
        {...this.state}
        className="Editable"
        onInput={this.handleInput} />
    );
  }
}

ReactDOM.render(
  <App />,
  demo
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id="demo"></div>

person Ori Drori    schedule 20.11.2017