web-dev-qa-db-ja.com

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はApp.jsテンプレートで作成された<div id="myId"></div>ノードにマウントされています。しかし、Appコンポーネントに無限の数のコンポーネントを追加する必要がある場合はどうなりますか?明らかに、必要なdivすべてをそこに置くことはできません。

いくつかのチュートリアルを読んでも、コンポーネントがどのように作成され、親コンポーネントに動的に追加されるのかについてはまだ理解できません。それを行う方法は何ですか?

57
Justin Trevein

このように、コンポーネントを子として渡す必要があります。

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

});
48

まず、 私は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を使用して必要なコンポーネントファイルにそれらをインポートすることで、プログラムで任意の数のコンポーネントと対話できます。

5
Chris

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

さて、以下のreturn()に直接{pushMessages}{emailMessages}を直接入れることも可能だと思いますが、もっと条件付きのコンテンツがあるとすれば、return()は雑然としているように見えます。

3
user888750

まず警告です。Reactによって管理されているDOMをいじってはいけません。ReactDOM.render(<SampleComponent ... />);を呼び出してやっています。

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

2
Neil Twist