Подтвердить что ты не робот

Динамически добавлять дочерние компоненты в React

Моя цель - динамически добавлять компоненты на страницу/родительский компонент.

Я начал с какого-то базового примера шаблона, например:

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 монтируется к узлу <div id="myId"></div>, который предварительно записан в шаблоне App.js. Но что, если мне нужно добавить неопределенное количество компонентов в компонент приложения? Очевидно, у меня не может быть всех необходимых дивов, сидящих там.

После прочтения некоторых руководств я все еще не понимаю, как компоненты создаются и добавляются в родительский компонент динамически. Как это сделать?

4b9b3361

Ответ 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 сделает это за вас. Если вы хотите добавить некоторые дочерние компоненты, вам просто нужно изменить реквизиты или указать, что это зависит от ситуации. Например:

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

});

Ответ 2

Во-первых, я бы не стал использовать 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.

Ответ 3

Во-первых, предупреждение: вы никогда не должны возиться с DOM, которым управляет React, который вы делаете, вызывая 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

Ответ 4

Разделите мое решение здесь, основываясь на ответе Криса. Надеюсь, это поможет другим.

Мне нужно было динамически добавлять дочерние элементы в мой 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() просто выглядел бы загроможденным.