首页 > 解决方案 > ContentEditable 没有更新虚拟 DOM

问题描述

我面临 contenteditable 无法更新虚拟 DOM 的问题。如果您看到下面的 gif,您将看到,通过单击加号图标,应在其旁边添加所选项目(我编辑过的)的副本,但正在制作该元素先前状态的副本。

我需要的行为是通过单击加号图标,应该制作更新元素的副本。

在此处输入图像描述

class TextInput extends React.Component {
    constructor(props) {
        super(props);
        let body = {bgColor:''};
        body.content = props.children ? props.children : '<span style="color:lightgrey !important; font-weight:light !important;">'+props.placeholder+'</span>';
        this.state = body;
    }

    focus(event){
        let target = event.target;
        target.style.outline = "2px dashed lightgray";
        if(target.innerText == target.getAttribute('placeholder')){
            this.setState({content:''});
        }
    }

    blur(event){
        let target = event.target;
        target.style.outline = "none";

        var html = target.innerHTML;
        if (this.props.onChange && html !== this.lastHtml) {
            this.props.onChange({
                target: {
                    value: html
                }
            });
        }
        this.lastHtml = html;

        this.setState({
            content:html
        });

        if( target.innerText == '' ){
            this.setState({content:'<span style="color:lightgrey !important; font-weight:light !important;">'+target.getAttribute('placeholder')+'</span>'});
        }
    }

    shouldComponentUpdate(nextProps){
        return nextProps.html !== ReactDOM.findDOMNode(this.refs.contentEditable).innerHTML;
    }

    change(event){
        let target = event.target;
        this.setState({
            content:target.innnerText
        });
    }

    render() {
        return <div>
            <div ref="contentEditable" contentEditable={true} dangerouslySetInnerHTML={{__html: this.state.content}} suppressContentEditableWarning={true} className="textarea" placeholder={this.props.placeholder} onMouseEnter={this.mouseEnter.bind(this)} onMouseLeave={this.mouseLeave.bind(this)} onFocus={this.focus.bind(this)} onBlur={this.blur.bind(this)}></div>
            <textarea onChange={this.change.bind(this)} name={this.props.name} value={this.state.content}></textarea>
        </div>;
    }
}

class EditorToolbar extends React.Component{
    render(){
        return <div className="hoverbox-container">
            <span className="hoverbox">
                <i className="fa fa-plus" onClick={this.props.evCopyElem}></i>
            </span>
        </div>;
    }
}

class Body extends React.Component{
    constructor() {
        super();

        this.state = {
           "summaries":[
              "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s. This is a new text.",
              "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."
           ]
        };

        this.state.activeElement = -1;
    }

    mouseEnter(index, event){
        this.setState({activeElement:index});
    }

    copy_elem(type, index, event){
        if( type == 'summaries' ){
            let arr = this.state[type];
            arr.splice(index, 0, arr[index]);
            this.setState({ summaries: arr });
        }
    }

    render(){
        var that = this;

        return <div>
            {
                this.state.summaries && this.state.summaries.length ? <Container fluid>
                    <Row>
                        { this.state.summaries.map(function(element, index){
                            return <Col xs={6} className="mb-25" key={index} onMouseEnter={that.mouseEnter.bind(that, 'summaries'+index)}>
                                {that.state.activeElement == 'summaries'+index ? <EditorToolbar evCopyElem={that.copy_elem.bind(that, 'summaries', index)} /> : ''}
                                <TextInput name='summaries' placeholder='Enter Overview, Job History, Activities and Summary'>{element}</TextInput>
                            </Col>;
                        }) }
                    </Row>
                    <br />
                </Container> : ''
            }
        </div>
    }
}

标签: javascriptreactjsecmascript-6contenteditablereact-dom

解决方案


您可以使用 aref来获取textarea. 我在 Stackblitz 上做了一个小复制,代码如下:

import React from "react";
import "./style.css";

export default function App() {
  const textareaRef = React.createRef();
  const [val, setVal] = React.useState();

  const copy = _ => {
    setVal(textareaRef.current.value);
  } 

  return (
    <div>
      <textarea ref={textareaRef}></textarea>
      <EditorToolbar copy={copy} />
      <hr />
      Copied Value: {val}
    </div>
  );
}

const EditorToolbar = ({copy}) => {
  return <button onClick={copy}>Copy</button>
}


推荐阅读