105 votes

Ajouter dynamiquement des composants enfants dans React

Mon objectif est d'ajouter des composants de manière dynamique sur une page/un composant parent.

J'ai commencé par un modèle d'exemple de base comme celui-ci :

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

Ici SampleComponent est monté sur <div id="myId"></div> qui est pré-écrit dans App.js modèle. Mais que faire si j'ai besoin d'ajouter un nombre indéfini de composants au composant App ? Il est évident que je ne peux pas avoir tous les divs assis là.

Après avoir lu quelques tutoriels, je n'ai toujours pas compris comment les composants sont créés et ajoutés au composant parent de manière dynamique. Quelle est la façon de procéder ?

2 votes

Y a-t-il une raison pour laquelle vos deux composants se montent sur des éléments différents ? 99% des applications React n'appellent que ReactDOM.render une fois et tous les autres composants sont des enfants du nœud "Root".

1 votes

Non, je comprends maintenant que ce n'est pas la bonne manière :)

81voto

Nikolai Mavrenkov Points 1086

Vous devez passer vos composants comme enfants, comme ceci :

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

Et ensuite les ajouter dans le corps du composant :

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

Vous n'avez pas besoin de manipuler manuellement le code HTML, React le fera pour vous. Si vous voulez ajouter des composants enfants, il vous suffit de changer les props ou l'état, cela dépend. Par exemple :

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 votes

Merci ! J'ai manqué le fait que les composants peuvent être définis dans render() en fonction de leur état. Votre réponse ici est la plus complète (elle mentionne le fait de remplir l'état avec des composants) et répond exactement à la question :)

0 votes

Comment transmettre des accessoires aux enfants qui ont été ajoutés ?

1 votes

Donc, si je veux créer une application à page unique comportant plusieurs onglets et fenêtres contextuelles à partir de boutons, je dois rendre ces composants (vides), les cacher (d'une manière ou d'une autre), puis modifier l'état pour les faire "apparaître" aux bons moments ? Si vous deviez essayer de créer une application à page unique et à onglets multiples en React, est-ce la meilleure façon de le faire ? Ou est-ce que quelque chose m'échappe ? Je vous remercie.

8voto

Je partage ici ma solution, basée sur la réponse de Chris. J'espère qu'elle pourra aider d'autres personnes.

J'avais besoin d'ajouter dynamiquement des éléments enfants dans mon JSX, mais d'une manière plus simple que les contrôles conditionnels dans mon instruction de retour. Je veux montrer un chargeur dans le cas où les éléments enfants ne sont pas encore prêts. Le voici :

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

Maintenant, je réalise que je pourrais aussi juste mettre {pushMessages} y {emailMessages} directement dans mon return() ci-dessous, mais en supposant que j'aie un contenu encore plus conditionnel, mon return() aurait juste l'air encombré.

7voto

Chris Points 426

D'abord, Je n'utiliserais pas document.body . Ajoutez plutôt un récipient vide :

index.html:

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

Choisissez alors de ne rendre que votre <App /> élément :

main.js:

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

Sur App.js vous pouvez importer vos autres composants et ignorer complètement votre code de rendu 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>
        );
    }
});

Vous pouvez ensuite interagir de manière programmatique avec un nombre quelconque de composants en les important dans les fichiers de composants nécessaires à l'aide de la fonction require .

0 votes

Pas de problème, je voyais bien quelqu'un copier-coller et passer des heures dessus...

6voto

Neil Twist Points 629

Tout d'abord, un avertissement : vous ne devriez jamais manipuler le DOM qui est géré par React, ce que vous faites en appelant ReactDOM.render(<SampleComponent ... />);

Avec React, vous devez utiliser SampleComponent directement dans l'application principale.

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

Le contenu de votre composant n'est pas pertinent, mais il doit être utilisé comme ceci :

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

Vous pouvez ensuite étendre votre composant d'application pour utiliser une liste.

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

Je vous recommande vivement de consulter la documentation React et de suivre les instructions "Get Started". Le temps que vous y consacrerez vous sera utile plus tard.

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

0 votes

Comment le tableau va-t-il remplir le composant enfant sans mappage ?

1 votes

@solanki... Un mapping n'est nécessaire que lorsque la liste n'est pas une liste de composants React. La liste ici est composée de deux SampleComponent qui ne nécessite donc pas de mappage. Si la liste était une liste de noms, alors elle nécessiterait un mappage vers des composants React.

0 votes

@solanki... Rappelez-vous que la sortie de la cartographie est simplement une autre liste

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X