Comment passer un composant React dans un autre composant React pour transclure le contenu du premier composant?

217

Existe-t-il un moyen de faire passer un composant dans un autre composant réactif? Je veux créer un composant de réaction de modèle et passer un autre composant de réaction afin de transclure ce contenu.

Edit: Voici un codepen reactJS illustrant ce que j'essaie de faire. http://codepen.io/aallbrig/pen/bEhjo

HTML

<div id="my-component">
    <p>Hi!</p>
</div>

ReactJS

/**@jsx React.DOM*/

var BasicTransclusion = React.createClass({
  render: function() {
    // Below 'Added title' should be the child content of <p>Hi!</p>
    return (
      <div>
        <p> Added title </p>
        {this.props.children}
      </div>
    )
  }
});

React.renderComponent(BasicTransclusion(), document.getElementById('my-component'));
Andrew Allbright
la source

Réponses:

198

Vous pouvez utiliser this.props.childrenpour rendre les enfants que le composant contient:

const Wrap = ({ children }) => <div>{children}</div>

export default () => <Wrap><h1>Hello word</h1></Wrap>
David Hellsing
la source
4
J'utiliserais cette réponse. this.props.childrenfait partie de l'API du composant et devrait être utilisé de cette façon. Les exemples de l'équipe React utilisent cette technique, comme pour transférer des accessoires et pour parler d'un seul enfant .
Ross Allen
De mon commentaire ci-dessous: En le passant comme accessoire, vous pouvez même lui donner un nom et utiliser propTypes pour taper check.
returneax
1
@AndrewAllbright: Votre exemple ne dépassait aucun enfant. Cela fonctionne: codepen.io/ssorallen/pen/Dyjmk
Ross Allen
Et au cas où vous voudriez alors obtenir les nœuds DOM des enfants: stackoverflow.com/questions/29568721/…
ericsoco
124

Notez que j'ai fourni une réponse plus approfondie ici

Enveloppe d'exécution:

C'est la manière la plus idiomatique.

const Wrapper = ({children}) => (
  <div>
    <div>header</div>
    <div>{children}</div>
    <div>footer</div>
  </div>
);

const App = () => <div>Hello</div>;

const WrappedApp = () => (
  <Wrapper>
    <App/>
  </Wrapper>
);

Notez qu'il childrens'agit d'un "accessoire spécial" dans React, et l'exemple ci-dessus est du sucre syntaxique et est (presque) équivalent à<Wrapper children={<App/>}/>


Wrapper d'initialisation / HOC

Vous pouvez utiliser un composant d'ordre supérieur (HOC). Ils ont été ajoutés récemment au document officiel .

// Signature may look fancy but it's just 
// a function that takes a component and returns a new component
const wrapHOC = (WrappedComponent) => (props) => (
  <div>
    <div>header</div>
    <div><WrappedComponent {...props}/></div>
    <div>footer</div>
  </div>
)

const App = () => <div>Hello</div>;

const WrappedApp = wrapHOC(App);

Cela peut conduire à (peu) de meilleures performances car le composant wrapper peut court-circuiter le rendu une longueur d'avance avec shouldComponentUpdate, tandis que dans le cas d'un wrapper d'exécution, le prop enfant est susceptible d'être toujours un ReactElement différent et de provoquer des re-rendus même si vos composants étendent PureComponent.

Notez que connectRedux était auparavant un wrapper d'exécution mais a été changé en HOC car cela permet d'éviter des rendus inutiles si vous utilisez l' pureoption (ce qui est vrai par défaut)

Vous ne devez jamais appeler un HOC pendant la phase de rendu car la création de composants React peut être coûteuse. Vous devriez plutôt appeler ces wrappers à l'initialisation.


Notez que lorsque vous utilisez des composants fonctionnels comme ci-dessus, la version HOC ne fournit aucune optimisation utile car les composants fonctionnels sans état n'implémentent pas shouldComponentUpdate

Plus d'explications ici: https://stackoverflow.com/a/31564812/82609

Sébastien Lorber
la source
29
const ParentComponent = (props) => {
  return(
    {props.childComponent}
    //...additional JSX...
  )
}

//import component
import MyComponent from //...where ever

//place in var
const myComponent = <MyComponent />

//pass as prop
<ParentComponent childComponent={myComponent} />
Joseph Barnes
la source
Cela aurait été correct si c'était le cas ... React 15.x vous interdit de retourner un composant multi-nœuds. React 16 (aka React Fibre) autorisera plusieurs nœuds. Voici le correctif pour votre exemple de code: const ParentComponent = (props) => ({props.childComponent}); importer MyComponent de //...where ever const myComponent = <MyComponent /> // passer en tant que prop <ParentComponent childComponent = {myComponent} />
Andrew Allbright
13

Facebook recommande l'utilisation de composants sans état Source: https://facebook.github.io/react/docs/reusable-components.html

Dans un monde idéal, la plupart de vos composants seraient des fonctions sans état, car à l'avenir, nous pourrons également effectuer des optimisations de performances spécifiques à ces composants en évitant les vérifications et les allocations de mémoire inutiles. C'est le modèle recommandé, lorsque cela est possible.

function Label(props){
    return <span>{props.label}</span>;
}

function Hello(props){
    return <div>{props.label}{props.name}</div>;
}

var hello = Hello({name:"Joe", label:Label({label:"I am "})});

ReactDOM.render(hello,mountNode);
Sud
la source
13

Vous pouvez le passer comme un accessoire normal: foo={<ComponentOne />}

Par exemple:

const ComponentOne = () => <div>Hello world!</div>
const ComponentTwo = () => (
  <div>
    <div>Hola el mundo!</div>
    <ComponentThree foo={<ComponentOne />} />
  </div>
)
const ComponentThree = ({ foo }) => <div>{foo}</div>
Fellow Stranger
la source
9

je préfère utiliser l'API intégrée React:

import React, {cloneElement, Component} from "react";
import PropTypes from "prop-types";

export class Test extends Component {
  render() {
    const {children, wrapper} = this.props;
    return (
      cloneElement(wrapper, {
        ...wrapper.props,
        children
      })
    );
  }
}

Test.propTypes = {
  wrapper: PropTypes.element,
  // ... other props
};

Test.defaultProps = {
  wrapper: <div/>,
  // ... other props
};

alors vous pouvez remplacer le div wrapper avec ce que vous voulez:

<Test wrapper={<span className="LOL"/>}>
  <div>child1</div>
  <div>child2</div>
</Test> 
Alnamrouti à prix réduit
la source
5

Vous pouvez passer un composant via. les accessoires et le rendre avec interpolation.

var DivWrapper = React.createClass({
    render: function() {
        return <div>{ this.props.child }</div>;
    }
});

Vous passeriez alors un propappelé child, qui serait un composant React.

returneax
la source
1
Cela conduirait à passer des composants via des attributs plutôt qu'en tant qu'enfants. Si vous utilisez this.props.childrencomme suggéré dans une autre réponse, vous pouvez écrire les enfants comme des enfants au lieu de attrs.
Ross Allen
1
@ssorallen vous n'avez pas dit pourquoi on est meilleur en aucune façon ... En le passant comme accessoire, vous pouvez même lui donner un nom et utiliser propTypes pour taper check.
returneax
1
Chaque élément que vous utilisez dans JSX n'est qu'un composant. S'ils utilisaient cette approche, vous ne seriez pas en mesure d'écrire même votre court exemple. Cela deviendrait <div child={this.props.child />.
Ross Allen
1
Découvrez la version JavaScript (ce que JSX en fait): jsfiddle.net/ssorallen/kvrxcqv8/2 . React.DOM.div, comme tous les composants principaux, utilise le childrentableau. Regardez comment il est utilisé dans votre Hellocomposant, il utilise déjà plusieurs enfants.
Ross Allen
20
L'inconvénient de poursuivre une discussion dans le chat est qu'ils ne sont pas archivés pour les futurs lecteurs.
ultrafez
3

Tard dans le jeu, mais voici un puissant modèle HOC pour remplacer un composant en le fournissant comme accessoire. C'est simple et élégant.

Supposons que le MyComponentrendu soit un Acomposant fictif mais que vous souhaitiez autoriser un remplacement personnalisé de A, dans cet exemple B, qui encapsule Aun <div>...</div>et ajoute également "!" à l'accessoire texte:

import A from 'fictional-tooltip';

const MyComponent = props => (
  <props.A text="World">Hello</props.A>
);
MyComponent.defaultProps = { A };

const B = props => (
  <div><A {...props} text={props.text + '!'}></div>
);

ReactDOM.render(<MyComponent A={B}/>);
joneit
la source
1

En fait, votre question est de savoir comment écrire un composant d'ordre supérieur (HOC). L'objectif principal de l'utilisation de HOC est d'empêcher le copier-coller. Vous pouvez écrire votre HOC en tant que composant purement fonctionnel ou en tant que classe, voici un exemple:

    class Child extends Component {
    render() {
        return (
            <div>
                Child
            </div>
        );
    }
}

Si vous souhaitez écrire votre composant parent en tant que composant basé sur une classe:

    class Parent extends Component {
    render() {
        return (
            <div>
                {this.props.children}
            </div>
        );
    }
}

Si vous souhaitez écrire votre parent en tant que composant fonctionnel:

    const Parent=props=>{
    return(
        <div>
            {props.children}
        </div>
    )
}
Meisam Nazari
la source
0

Voici un exemple d'un composant de réaction List parent et dont les accessoires contiennent un élément React. Dans ce cas, un seul composant React Link est transmis (comme indiqué dans le rendu dom).

class Link extends React.Component {
  constructor(props){
    super(props);
  }
  render(){
    return (
      <div>
        <p>{this.props.name}</p>
      </div>
     );
  }
}
class List extends React.Component {
  render(){
   return(
    <div>
       {this.props.element}
       {this.props.element}
    </div>
   );
  }
}

ReactDOM.render(
  <List element = {<Link name = "working"/>}/>,
  document.getElementById('root')
);
cheesey
la source
0

Oui, vous pouvez le faire en utilisant des accessoires, vous pouvez passer des données de composant en tant qu'objet comme des accessoires, puis à l'intérieur du composant, vous pouvez importer un autre composant et lier dynamiquement avec des données prpps. en savoir plus sur le composant react

Dipankar Dutta
la source
1
pouvez-vous élaborer avec du code à partir du lien que vous avez publié
Nelles