【问题标题】:Uncaught Invariant Violation: Target container is not a DOM element未捕获的不变违规:目标容器不是 DOM 元素
【发布时间】:2019-07-16 21:48:22
【问题描述】:

这是我创建复选框输入样式的组件。 一切正常,但出现此错误消息,我不知道为什么。

'未捕获的不变违规:目标容器不是 DOM 元素。'

Stackoverflow 要求我在提交此问题之前发布更多 cmets,但我确实没有更多信息可在此处设置...所以我将在此问题中发布我正在使用的版本。

React 版本:React v16.8.3

React DOM 版本:React v16.8.3

巴别塔:https://unpkg.com/babel-standalone@6.15.0/babel.min.js

    /* global ReactDOM, React */

    class Switch3dPermissao extends React.Component {

      constructor(props) {
        super(props);
        this.state = { checked: props.defaultChecked };
      }

      toggle = () => {
        this.setState({
          checked: !this.state.checked
        })
      }

      render() {

        return (
          <div>
            <label className={'mr-3 switch switch-3d switch-'+this.props.type}>
              <input type="hidden" name={this.props.id} value={this.props.offvalue} />
              <input
                id={this.props.id}
                name={this.props.id}
                value={this.props.value}
                className="switch-input"
                type="checkbox"
                checked={ this.state.checked ? true : false }
                onChange={ this.toggle }
              />
              <span className="switch-label"></span>
              <span className="switch-handle"></span>
            </label>
            <label htmlFor={ this.props.id } className="cursor-pointer" dangerouslySetInnerHTML={{ __html: this.props.html }}></label>
          </div>
        );
      }
    }

    // Elementos com esta classe
    var els = document.getElementsByClassName('switch-3d-permissao');

    for (var i in els) {

      var element = els[i];

      // Is default checked?
      var isChecked = false;
      var value = '1';
      if (element.attributes !== undefined) {

        if (element.attributes.checked !== undefined) {
          isChecked = true;
        }

        if (element.attributes.value !== undefined) {
          value = element.attributes.value.textContent;
        }
      }

      var id = null;
      var type = 'danger';
      var offvalue = '0';
      if (element.dataset !== undefined) {

        // data-id (The form checkbox id)
        if (element.dataset.id !== undefined) {
          id = element.dataset.id;
        }

        // data-type warning | danger | primary | info | success
        if (element.dataset.type !== undefined) {
          type = element.dataset.type;
        }

        // Valor para quando o checkbox nao esta checado
        if (element.dataset.offvalue !== undefined) {
          offvalue = element.dataset.offvalue;
        }
      }

      ReactDOM.render(<Switch3dPermissao id={id} type={type} html={element.innerHTML} defaultChecked={isChecked} value={value} offvalue={offvalue} />, element)
    }

【问题讨论】:

  • 你想完成什么?我认为您正在混合反应和非反应的做事方式。 React 正在处理虚拟 DOM 并在状态更改时重新渲染元素,但是当您使用 getElementsByClassName 时直接操作 DOM,这不是正确的方法。
  • 您是否有理由直接在元素上添加属性?您可以将这些保存在状态中。
  • 我从 html 获取元素属性,因此当有人需要使用我的代码时,只需传递属性值即可根据需要创建元素。什么是“正确”的做法?
  • 您可以将它们作为道具传递。假设您正在创建一个引导按钮,然后您想更改按钮的颜色,您可以将道具设置为“变体”,然后您可以传递“成功”或“危险”。您还可以在状态和按钮重新渲染中相应地更改这些。作为一般经验法则,您通常需要避免在 React 应用程序中直接操作 DOM
  • 好的,给我几分钟。

标签: javascript html reactjs babeljs


【解决方案1】:

这是因为使用 for..in 迭代 NodeListfor..in 循环还迭代对象的不可枚举属性,包括长度,这会给您错误,即目标容器不是 DOM 元素。

要解决此问题,您可以使用for..of 循环来循环仅拥有它自己的属性。

/* global ReactDOM, React */

class Switch3dPermissao extends React.Component {

  constructor(props) {
    super(props);
    this.state = { checked: props.defaultChecked };
  }

  toggle = () => {
    this.setState({
      checked: !this.state.checked
    })
  }

  render() {

    return (
      <div>
        <label className={'mr-3 switch switch-3d switch-'+this.props.type}>
          <input type="hidden" name={this.props.id} value={this.props.offvalue} />
          <input
            id={this.props.id}
            name={this.props.id}
            value={this.props.value}
            className="switch-input"
            type="checkbox"
            checked={ this.state.checked ? true : false }
            onChange={ this.toggle }
          />
          <span className="switch-label"></span>
          <span className="switch-handle"></span>
        </label>
        <label htmlFor={ this.props.id } className="cursor-pointer" dangerouslySetInnerHTML={{ __html: this.props.html }}></label>
      </div>
    );
  }
}

// Elementos com esta classe
var els = document.getElementsByClassName('switch-3d-permissao');

for (var element of els) {


  // Is default checked?
  var isChecked = false;
  var value = '1';
  if (element.attributes !== undefined) {

    if (element.attributes.checked !== undefined) {
      isChecked = true;
    }

    if (element.attributes.value !== undefined) {
      value = element.attributes.value.textContent;
    }
  }

  var id = null;
  var type = 'danger';
  var offvalue = '0';
  if (element.dataset !== undefined) {

    // data-id (The form checkbox id)
    if (element.dataset.id !== undefined) {
      id = element.dataset.id;
    }

    // data-type warning | danger | primary | info | success
    if (element.dataset.type !== undefined) {
      type = element.dataset.type;
    }

    // Valor para quando o checkbox nao esta checado
    if (element.dataset.offvalue !== undefined) {
      offvalue = element.dataset.offvalue;
    }
  }

  ReactDOM.render(<Switch3dPermissao id={id} type={type} html={element.innerHTML} defaultChecked={isChecked} value={value} offvalue={offvalue} />, element)
}
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div class="switch-3d-permissao" data-id="status" checked>Pode fazer login no sistema?</div>

methods of iteration docs from MDN

【讨论】:

  • 实际上,这很奇怪,但我的代码中没有这个“of”... =/ 我猜是 'code sn-p' 做到了... õ.O 我会尝试修复它
  • @MarcoA.Braghim 对不起,我的错误。描述被颠倒了。已编辑以修复该问题
【解决方案2】:

这里有一个简单的例子来展示如何从状态改变样式。

class Sample extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      test: true,
      color: 'success'
    };

    this.handleInputChange = this.handleInputChange.bind(this);
  }

  handleInputChange(event) {
    const target = event.target;
    const name = target.name;
    const value = target.checked

    this.setState({
      [name]: value,
      color: value ? 'success' : 'danger'
    });
    
  }

  render() {
    return (
      <form>
        <label>
          Test:
          <input
            name="test"
            type="checkbox"
            checked={this.state.test}
            onChange={this.handleInputChange} />
        </label>
        <ReactBootstrap.Button className='ml-3' variant={this.state.color}>Test</ReactBootstrap.Button>
      </form>
    );
  }
}

ReactDOM.render(
  <Sample />,
  document.getElementById('root')
);
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/react-bootstrap@next/dist/react-bootstrap.min.js" crossorigin></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap.min.css" crossorigin="anonymous">

<div id="root" />

【讨论】:

  • 嗯,非常感谢,肯定会非常有用!但我的项目与 jQuery 混合,所以我没有“根”div 或类似的东西,让我解释一下我的 porpose 是什么。
  • 我有一个共同的项目,包含 html、php、css、js、jquery 以及你所知道的一切,它是一个免费的引导模板......我想在我的生活中一步一步地应用 react 因为完成项目的截止日期。
  • 所以我正在创建小的独立组件,以便根据需要单独和重复使用。在 HTML 上,我希望能够指出组件需要如何呈现元素:
    所以不需要更改JS文件组件来制作它。我很难理解如何去做,因为这对我来说是一个新世界。也许我想念你的意思,如果是这样,请告诉我。
  • 正如我所说,您需要避免在 React 应用程序中使用直接 DOM 操作。一旦状态改变,React 会重新渲染你的页面。您可以完全避免在您的情况下使用 jQuery。如您所见,通过状态更改元素样式非常容易。这种方法可以扩展到其他属性。如果您想逐步将您的应用程序迁移到 React,我建议您逐页执行此操作,而不是更改页面的一部分。这可以帮助你思考 React 是如何工作的并重建你的页面。然后逐渐你也可以在其他页面上使用你的组件。
【解决方案3】:

我找到了解决方案。需要检查 FOR 循环上的元素是否为 DOM 元素,如果不是则继续下一个。


  var els = document.getElementsByClassName('switch-3d-permissao');

  for (var i in els) {
    var element = els[i];

    // Check if it is an object
    if (typeof element !== 'object') {
      continue;
    }

    // ...
  }

【讨论】:

    猜你喜欢
    相关资源
    最近更新 更多
    热门标签