在 React 中动态添加子组件

IT技术 javascript reactjs babeljs
2021-04-04 22:55:49

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

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

主要.js:

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

应用程序.js:

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

        );
    }

});

示例组件.js:

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

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

在阅读了一些教程后,我仍然不了解组件是如何动态创建和添加到父组件的。这样做的方法是什么?

4个回答

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

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>
        );
    }

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

首先,我不会使用 document.body而是添加一个空容器:

index.html:

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

然后选择仅呈现您的<App />元素:

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.

没问题,我可以看到有人复制粘贴它,然后花几个小时在上面......
2021-06-15 22:55:49

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

我需要动态地将子元素附加到我的 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()看起来会很混乱。

首先是一个警告:你永远不应该修改由 React 管理的 DOM,你正在通过调用 ReactDOM.render(<SampleComponent ... />);

使用 React,您应该直接在主应用程序中使用 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... 请记住,映射的输出只是另一个列表
2021-05-24 22:55:49
正是我要找的。我的用例需要有选择地将 JSX 组件推入一个<div>分配给一个变量的空中,然后该变量被插入到 JSX 中,就像{content}在我的 return 语句中一样。使用空数组是如此简单!
2021-05-29 22:55:49
数组将如何在没有映射的情况下填充子组件?
2021-06-02 22:55:49
@solanki... 仅当列表不是 React 组件列表时才需要映射。这里的列表有两个SampleComponents,因此不需要映射。如果列表是名称列表,则需要映射到 React 组件。
2021-06-02 22:55:49