在React中更新状态时出现问题

时间:2017-11-20 18:07:46

标签: javascript reactjs state caret

请在我说明问题的地方查看我的小提琴

这是我的小提琴: https://jsfiddle.net/jajabya/fb93f7b0/

我的goad是获取input标记,其中包含特殊字词(例如日期或用户名称可以通过包裹在span标记中突出显示)

div一定存在问题,因为当我使用输入字段时,一切正常。

我的问题是我不能让插入符号出现在正确的位置 每次状态在onInput

中更新时
  onInput(event) {
    this.setState({
        html: event.target.innerText.toUpperCase()  
    });

  }

插入符号回滚到开头

1 个答案:

答案 0 :(得分:4)

我的想法是将当前插入符号位置保存在状态中,并通过componentDidUpdate()中的引用将其设置回来(因为引用不会重新呈现组件)。

注意:这是一个原型想法,我从来没有经过测试,所以请谨慎使用。

插入符号位置代码取自以下答案:

  1. Code for getting the caret position

  2. Code for setting caret position

  3. 
    
    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
    );
    &#13;
    <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>
    &#13;
    &#13;
    &#13;