【问题标题】:ReactJS - PopUp Component Error: Target container is not a DOM elementReactJS - 弹出组件错误:目标容器不是 DOM 元素
【发布时间】:2015-06-22 13:34:23
【问题描述】:

我在这里尝试在 ReactJS 中制作组件以创建弹出窗口,但我在 react-with-addons.js 中收到此错误:

错误:不变违规:_registerComponent(...):目标容器不是 DOM 元素。

这是我的代码:

HTML:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8"> 
    <script type="text/javascript" src="react-0.13.3/build/react-with-addons.js"></script>
    <script type="text/javascript" src="react-0.13.3/build/JSXTransformer.js"></script>
    <script type="text/javascript" src="react-router/lib/umd/ReactRouter.js"></script>
    <link rel="stylesheet" href="bootstrap/css/bootstrap.min.css"/>
    <link rel="stylesheet" href="bootstrap/css/bootstrap-theme.min.css"/>

    <script type="text/javascript" src="jquery/jquery-1.11.1.min.js"></script>
    <script type="text/javascript" src="bootstrap/js/bootstrap.min.js"></script>

    <title>WS-JAVA-REST</title>

    <style>
        .row { padding-top: 10px; }
    </style>
  </head>
  <body>
    <!-- contenu -->
    <div id="content">
        <script type="text/jsx" src="test.js"></script>
    </div>
  </body>
</html>

Javascript

/** @jsx React.DOM */

var clicked = function(){
  mountedPopup.setState({visible: true, pretendStateChanged: Date.now() });
  mountedComponent.setState({pretendStateChanged: Date.now() }) ;
}

var popupClicked = function(){
  mountedPopup.setState({visible: false, pretendStateChanged: Date.now() });
  mountedComponent.setState({pretendStateChanged: Date.now() }) ;
};

var Component = React.createClass({
  getInitialState: function() {
    return {pretendStateChanged: Date.now() };
  },
  render: function(){
    return React.DOM.div(null,
      React.DOM.a({onClick: clicked, href: "javascript:void(0);"}, "Show popup"),
      React.DOM.br(null),
      React.DOM.span(null, "State: " + this.state.pretendStateChanged)
    );
  }
});

var Popup = React.createClass({
  getInitialState: function() {
    return {visible: false, pretendStateChanged: Date.now()};
  },
  componentWillUpdate: function(nextProps, nextState){
    if (!this.state.visible && nextState.visible) {
      this.popUp();
    }

    /* closed by application */
    if (this.state.visible && !nextState.visible) {
      this.closePopUp();
    }
  },
  popUp: function(){
    var self  = this;
    var parent = this.getDOMNode().parentNode;
    $.magnificPopup.open({
      items: {
        src: parent,
        type: 'inline'
      },
      removalDelay: 30,
      callbacks: {
        afterClose: function() {
          if (self.state.visible){
            /* closed by user pressing ESC */
            self.setState({visible: false});
          }
        }
      }
    });
  },
  closePopUp: function(){
    $.magnificPopup.close();
  },
  render: function(){
    return React.DOM.div(null,
      React.DOM.a({
        onClick: this.props.onClickHandler,
        href: "javascript:void(0);"
      }, "Button inside popup"),
      React.DOM.br(null),
      React.DOM.span(null, "State: " + this.state.pretendStateChanged)
    );
  }
});

var mountedComponent = React.render(
  <Component/>,
  document.body.childNodes[1]
);

var mountedPopup = React.render(
  <Popup onClickHandler={this.popupClicked} />,
  document.body.childNodes[3]
);

所以我完全错过了什么吗?为什么我会收到此错误?有人可以帮我吗?

【问题讨论】:

  • 为什么要使用这个脆弱的选择器document.body.childNodes[1]?试试document.getElementById('content')。将脚本标签放在&lt;body&gt; 的底部也是正常的做法(不在该内容元素内)。此外,您在 html 文档中有一个元素,document.body.childNodes[3] 的目标是什么?您也在使用 jsx,但随后使用普通 js 编写元素(例如React.DOM.br.. jsx 使它更像 html,那么为什么不使用它呢?
  • 是的,你说得对,我不知道为什么我一开始就写了...我在 2 渲染中更改了你告诉我的内容:&lt;div&gt; But &lt;a onClick={this.clicked}&gt; Show popup&lt;/a&gt; State: &lt;span&gt;{this.state.pretendStateChanged}&lt;/span&gt; &lt;/div&gt; 和:document.getElementById('content') 但我还是一样的错误
  • render 调用放入$(document).ready(function() { /* put here */ })。错误消息的意思是,他找不到安装元素。这可能是因为您尝试在加载 DOM 之前运行代码。
  • 我猜你正在尝试将弹出窗口附加到在组件中生成反应的一些 html(在它被渲染之前) - 我的建议是不要混合 jQuery 和反应在一起。无需任何插件即可轻松制作弹出窗口。如果你正确使用 react 就不会遇到这些问题,因为会有合适的渲染树。

标签: javascript jquery popup reactjs react-jsx


【解决方案1】:

您的问题的简短回答是原始组件尚未加载,因此没有目标 DOM 节点来加载 Popup 组件。 React.render 有一个可选的第三个参数,用于在渲染完成时触发的回调。因此,以下内容应该适用于您的情况:

var mountedPopup;
var mountedComponent = React.render(
  <Component/>,
  document.body.childNodes[1],
  function() {
     mountedPopup = React.render(
        <Popup onClickHandler={this.popupClicked} />,
        document.body.childNodes[3]
     );
  }
);

但是,正如其他人所提到的,对于此代码也有一些重要的建议:

  1. 绝对不要使用 document.body.childNodes[N] 作为语法
  2. 您应该尽可能避免使用弹出窗口的库...jQuery 和 React 并不总是能很好地配合使用
  3. 您将其结构化为两个单独的组件,并使用全局变量和函数将它们联系在一起。将弹出组件作为另一个组件的子组件,这可能会更好地构建。这样,您将能够使用父组件来管理状态,并且弹出窗口可以响应这些更改。它还允许您将大量代码封装在父组件中。如果这样做,您将不需要通过变量名来引用这些组件,甚至不需要为它们分配变量。这是一种反模式,应该避免。
  4. “this.popupClicked”可能无法按预期工作。由于它是一个全局函数,您可以将其称为“popupClicked”。更好的是,您最终应该将其作为方法合并到您的父容器中(见上文)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-17
    • 1970-01-01
    • 2014-12-12
    • 1970-01-01
    • 2021-06-02
    相关资源
    最近更新 更多