Reactに子コンポーネントを動的に追加する


89

私の目標は、ページ/親コンポーネントにコンポーネントを動的に追加することです。

私はこのようないくつかの基本的なサンプルテンプレートから始めました:

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テンプレート。しかし、Appコンポーネントに無数のコンポーネントを追加する必要がある場合はどうなりますか?明らかに、必要なすべてのdivをそこに配置することはできません。

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


2
両方のコンポーネントが異なる要素にマウントされる理由はありますか?Reactアプリの99%はReactDOM.render一度だけ呼び出し、他のすべてのコンポーネントは「ルート」ノードの子です
azium 2016

1
いいえ、これは正しい方法ではないことを理解しました:)
Justin Trevein 2016

回答:


70

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

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
ありがとう!コンポーネントがその状態に基づいてrender()で定義できるという事実を見逃しました。ここでのあなたの答えは最も完全なものであり(状態にコンポーネントが入力されていることに言及)、質問に正確に答えます:)
Justin Trevein 2016

追加された子供たちに小道具をどのように渡しますか?
BrightIntelDusk 2017

1
したがって、これをフォローアップするには、複数のタブとボタンからのポップアップウィンドウを備えたシングルページアプリを作成する場合は、先に進んでそれらのコンポーネントをレンダリングし(空)、非表示にし(何らかの方法で)、状態を変更して作成する必要がありますそれらは適切なタイミングで「表示」されますか?Reactでマルチタブのシングルページアプリを作成しようとすると、それが最善の方法ですか?それとも私は何かが足りないのですか?ありがとうございました!
エリザベス

1
@Elisabethはい、そうです。実際には、2つの主なオプションがあります。常にすべてをレンダリングし、CSSを使用して非表示にするか、CSSクラスまたはインラインスタイルを条件付きで適用します。または、条件付きでレンダリングし、アプリの状態に応じてReact要素またはnullを返します。これらの2つのアプローチには長所と短所があり、ニーズに応じて異なるコンポーネントの同じアプリで両方を使用することがよくあります。
Nikolai Mavrenkov 2018年

1
ニコライありがとう!それは本当にReactについての私の心の中で物事を固めるのに役立ちます。これは、私がプレーンJavaScriptやjQueryで使用している方法とは、アプリを設計してDOMについて考える方法とは大きく異なります。
エリザベス

7

まず、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


いいえ問題は、私はちょうど誰かにそれをコピー&ペーストし、それに時間を費やして見ることができなかった...
ニールはツイスト

6

クリスの答えに基づいて、ここで私の解決策を共有します。それが他の人を助けることができることを願っています。

子要素を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()ただ雑然となります。


4

最初の警告: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 ... 2016

1
@solanki ...マッピングは、リストがReactコンポーネントのリストではない場合にのみ必要です。ここでのリストは2つSampleComponentであるため、マッピングは必要ありません。リストが名前のリストである場合、Reactコンポーネントへのマッピングが必要になります。
ニールツイスト2016

@solanki ...マッピングの出力は単なる別のリストであることを忘れないでください
Neil Twist

1
まさに私が探していたもの。私のユースケースでは、オプションでJSXコンポーネントを<div>変数に割り当てられた空にプッシュ{content}し、returnステートメントのようにJSXに挿入する必要がありました。空の配列の使用はとても簡単でした!
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.