【问题标题】:Dynamically add child components in React在 React 中动态添加子组件
【发布时间】:2016-04-15 15:48:06
【问题描述】:

我的目标是在页面/父组件上动态添加组件。

我从一些基本的示例模板开始,如下所示:

main.js:

var App = require('./App.js');
var SampleComponent = require('./SampleComponent.js');
ReactDOM.render(<App/>, document.body);
ReactDOM.render(<SampleComponent name="SomeName"/>, document.getElementById('myId'));

App.js:

var App = React.createClass({
    render: function() {
        return (
            <div>
                <h1>App main component! </h1>
                <div id="myId">myId div</div>
            </div>

        );
    }

});

SampleComponent.js:

var SampleComponent = React.createClass({
    render: function() {
        return (
            <div>
                <h1>Sample Component! </h1>
            </div>
        );
    }
});

这里SampleComponent 挂载到&lt;div id="myId"&gt;&lt;/div&gt; 节点,该节点是预先写在App.js 模板中的。但是如果我需要向 App 组件添加不定数量的组件怎么办?显然,我不能将所有必需的 div 都放在那里。

在阅读了一些教程之后,我仍然不了解组件是如何动态创建并添加到父组件的。有什么办法?

【问题讨论】:

  • 您的两个组件都安装到不同的元素是否有原因? 99% 的 React 应用只调用一次ReactDOM.render,所有其他组件都是“根”节点的子节点
  • 不,我现在明白这不是正确的方法:)

标签: javascript reactjs babeljs


【解决方案1】:

您需要将组件作为子组件传递,如下所示:

var App = require('./App.js');
var SampleComponent = require('./SampleComponent.js');
ReactDOM.render(
    <App>
        <SampleComponent name="SomeName"/> 
    <App>, 
    document.body
);

然后将它们附加到组件的主体中:

var App = React.createClass({
    render: function() {
        return (
            <div>
                <h1>App main component! </h1>
                {
                    this.props.children
                }
            </div>
        );
    }
});

您不需要手动操作 HTML 代码,React 会为您完成。如果你想添加一些子组件,你只需要改变它所依赖的 props 或 state。例如:

var App = React.createClass({

    getInitialState: function(){
        return [
            {id:1,name:"Some Name"}
        ]
    },

    addChild: function() {
        // State change will cause component re-render
        this.setState(this.state.concat([
            {id:2,name:"Another Name"}
        ]))
    }

    render: function() {
        return (
            <div>
                <h1>App main component! </h1>
                <button onClick={this.addChild}>Add component</button>
                {
                    this.state.map((item) => (
                        <SampleComponent key={item.id} name={item.name}/>
                    ))
                }
            </div>
        );
    }

});

【讨论】:

  • 谢谢!我错过了可以根据状态在 render() 中定义组件的事实。您在这里的答案是最完整的(提到用组件填充状态)并准确回答了问题:)
  • 如何将 props 传递给已附加的孩子?
  • 所以要跟进这一点:如果我想制作一个具有多个选项卡和按钮弹出窗口的单页应用程序,我需要继续渲染这些组件(空),隐藏它们(不知何故)然后修改状态以使它们在正确的时间“出现”?如果你要尝试在 React 中制作一个多标签单页应用程序,这是最好的想法吗?还是我错过了什么?谢谢!
  • @Elisabeth 是的,没错。你实际上有两个主要选择:要么总是渲染所有东西,要么只使用 CSS 隐藏东西,有条件地应用 CSS 类或内联样式;或有条件地渲染事物,根据您的应用程序状态返回 React 元素或 null。这两种方法各有利弊,通常根据您的需要在同一个应用程序中用于不同的组件。
  • 谢谢尼古拉!这确实有助于巩固我对 React 的看法。与我使用纯 JavaScript 和 jQuery 相比,这是一种设计应用程序和思考 DOM 的非常不同的方式。
【解决方案2】:

根据 Chris 的回答,在这里分享我的解决方案。希望它可以帮助其他人。

我需要动态地将子元素附加到我的 JSX 中,但比我的 return 语句中的条件检查更简单。我想在子元素还没有准备好的情况下显示一个加载器。这里是:

export class Settings extends React.PureComponent {
  render() {
    const loading = (<div>I'm Loading</div>);
    let content = [];
    let pushMessages = null;
    let emailMessages = null;

    if (this.props.pushPreferences) {
       pushMessages = (<div>Push Content Here</div>);
    }
    if (this.props.emailPreferences) {
      emailMessages = (<div>Email Content Here</div>);
    }

    // Push the components in the order I want
    if (emailMessages) content.push(emailMessages);
    if (pushMessages) content.push(pushMessages);

    return (
      <div>
        {content.length ? content : loading}
      </div>
    )
}

现在,我确实意识到我也可以将{pushMessages}{emailMessages} 直接放在下面的return() 中,但假设我有更多的条件内容,我的return() 看起来会很混乱。

【讨论】:

    【解决方案3】:

    首先,I wouldn't use document.body。而是添加一个空容器:

    index.html:

    <html>
        <head></head>
        <body>
            <div id="app"></div>
        </body>
    </html>
    

    然后选择只呈现您的 &lt;App /&gt; 元素:

    main.js:

    var App = require('./App.js');
    ReactDOM.render(<App />, document.getElementById('app'));
    

    App.js 中,您可以导入其他组件并完全忽略您的 DOM 渲染代码:

    App.js:

    var SampleComponent = require('./SampleComponent.js');
    
    var App = React.createClass({
        render: function() {
            return (
                <div>
                    <h1>App main component!</h1>
                    <SampleComponent name="SomeName" />
                </div>
            );
        }
    });
    

    SampleComponent.js:

    var SampleComponent = React.createClass({
        render: function() {
            return (
                <div>
                    <h1>Sample Component!</h1>
                </div>
            );
        }
    });
    

    然后,您可以通过使用require 将它们导入必要的组件文件,以编程方式与任意数量的组件进行交互。

    【讨论】:

      【解决方案4】:

      首先警告:你永远不应该修补由 React 管理的 DOM,你正在通过调用 ReactDOM.render(&lt;SampleComponent ... /&gt;); 来做这件事

      使用 React,您应该直接在主 App 中使用 SampleComponent。

      var App = require('./App.js');
      var SampleComponent = require('./SampleComponent.js');
      ReactDOM.render(<App/>, document.body);
      

      你的组件的内容无关紧要,但应该这样使用:

      var App = React.createClass({
          render: function() {
              return (
                  <div>
                      <h1>App main component! </h1>
                      <SampleComponent name="SomeName"/>
                  </div>
              );
          }
      });
      

      然后您可以扩展您的应用组件以使用列表。

      var App = React.createClass({
          render: function() {
              var componentList = [
                  <SampleComponent name="SomeName1"/>,
                  <SampleComponent name="SomeName2"/>
              ]; // Change this to get the list from props or state
              return (
                  <div>
                      <h1>App main component! </h1>
                      {componentList}
                  </div>
              );
          }
      });
      

      我真的建议您查看 React 文档,然后按照“入门”说明进行操作。你花在这上面的时间会在以后得到回报。

      https://facebook.github.io/react/index.html

      【讨论】:

      • 数组如何在没有映射的情况下填充子组件?
      • @solanki... 仅当列表不是 React 组件列表时才需要映射。这里的列表是两个SampleComponents,因此不需要映射。如果列表是名称列表,则需要映射到 React 组件。
      • @solanki... 请记住,映射的输出只是另一个列表
      • 正是我想要的。我的用例需要选择性地将 JSX 组件推送到分配给一个变量的空 &lt;div&gt; 中,然后在我的 return 语句中将其作为 {content} 插入 JSX。使用空数组非常简单!
      猜你喜欢
      • 2022-01-17
      • 2018-07-02
      • 2019-01-15
      • 2021-04-05
      • 2019-08-08
      • 2018-09-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-25
      相关资源
      最近更新 更多