渲染ContentEditable组件而不获取ContentEditableWarning?

时间:2018-03-30 22:05:06

标签: javascript reactjs

渲染我的组件时收到以下警告:

  

警告:组件为contentEditable且包含children   由React管理。现在你有责任保证不这样做   这些节点的意外修改或重复。这是   可能不是故意的。

这是我的组成部分:

import React, { Component } from "react";

export default class Editable extends Component {
  render() {
    return (
      <div contentEditable={true} onBlur={this.props.handleBlur}>
        {this.props.children}
      </div>
    );
  }
}

来自https://github.com/lovasoa/react-contenteditable的此组件不会生成警告。

import React from 'react';

let stripNbsp = str => str.replace(/&nbsp;|\u202F|\u00A0/g, ' ');

export default class ContentEditable extends React.Component {
  constructor() {
    super();
    this.emitChange = this.emitChange.bind(this);
  }

  render() {
    var { tagName, html, ...props } = this.props;

    return React.createElement(
      tagName || 'div',
      {
        ...props,
        ref: (e) => this.htmlEl = e,
        onInput: this.emitChange,
        onBlur: this.props.onBlur || this.emitChange,
        contentEditable: !this.props.disabled,
        dangerouslySetInnerHTML: {__html: html}
      },
      this.props.children);
  }

  shouldComponentUpdate(nextProps) {
    let { props, htmlEl } = this;

    // We need not rerender if the change of props simply reflects the user's edits.
    // Rerendering in this case would make the cursor/caret jump

    // Rerender if there is no element yet... (somehow?)
    if (!htmlEl) {
      return true;
    }

    // ...or if html really changed... (programmatically, not by user edit)
    if (
      stripNbsp(nextProps.html) !== stripNbsp(htmlEl.innerHTML) &&
      nextProps.html !== props.html
    ) {
      return true;
    }

    let optional = ['style', 'className', 'disabled', 'tagName'];

    // Handle additional properties
    return optional.some(name => props[name] !== nextProps[name]);
  }

  componentDidUpdate() {
    if ( this.htmlEl && this.props.html !== this.htmlEl.innerHTML ) {
      // Perhaps React (whose VDOM gets outdated because we often prevent
      // rerendering) did not update the DOM. So we update it manually now.
      this.htmlEl.innerHTML = this.props.html;
    }
  }

  emitChange(evt) {
    if (!this.htmlEl) return;
    var html = this.htmlEl.innerHTML;
    if (this.props.onChange && html !== this.lastHtml) {
      // Clone event with Object.assign to avoid 
      // "Cannot assign to read only property 'target' of object"
      var evt = Object.assign({}, evt, { 
        target: { 
          value: html 
        } 
      });
      this.props.onChange(evt);
    }
    this.lastHtml = html;
  }
}

问题:

  • React想要警告我的代码有什么潜在问题?我在阅读https://reactjs.org/docs/dom-elements.html的文档时并不太了解。
  • 为什么https://github.com/lovasoa/react-contenteditable的组件不会生成相同的警告?

3 个答案:

答案 0 :(得分:4)

您说明的组件正在生成调用React.createElement的组件,如下所示 从而避免出现警告:

function ContentEditable(props) {
  return React.createElement('div', {contentEditable: true});
}

您正在使用jsx。

function ContentEditable(props) {
  return (<div contentEditable={true}></div>);
}

您可以阅读更多关于here为什么做出反应的信息 警告您。如果您想取消警告,也可以使用 suppressContentEditableWarning属性。

function ContentEditable(props) {
  return (<div contentEditable={true} suppressContentEditableWarning={true}></div>);
}

答案 1 :(得分:1)

设置contenteditable时,就是要在浏览器中修改内容。

如果您更改DOM而没有React的管理,React会警告您,因为这可能会在例如更新这些元素时引起问题。您正在传递直接来自React的{this.props.children},使用contenteditable会让用户在浏览器中修改您的内容,因此可能与React不再具有控制权不同。

您可以使用suppressContentEditableWarning={true}来避免该警告。 您可以使用React.createElement并传递参数{contentEditable: true}来避免警告(就像https://github.com/lovasoa/react-contenteditable一样)

答案 2 :(得分:0)

我不使用外部组件。我也遇到了同样的问题,此外,如果我将div标记为可编辑的内容,我经常会收到这样的错误消息:我不能危险地使用SetInnerHTML。我的方法与您类似。因此,我没有将其标记为可编辑内容。只是危险地设置InnerHTML。但是在componentDidUpdate中,我使用了ref来将div的setAttribute设置为“ contenteditable = true”。我使用了相同的div来获取要保存的div内容。这样就停止了所有警告和错误。

componentDidUpdate(){
    this.htmlEl.setAttribute("contenteditable", true);
}

此外,如果您的危险SetInnerHTML内容包含反应组件,则可以对它们进行水合处理以使其起作用。但是显然,您需要知道div中的哪些成分可以对其进行水合。