¿Cómo pasar un componente de reacción a otro componente de reacción para transcluir el contenido del primer componente?


215

¿Hay alguna manera de pasar un componente a otro componente de reacción? Quiero crear un modelo de componente de reacción y pasar otro componente de reacción para poder incluir ese contenido.

Editar: Aquí hay un codepen reactJS que ilustra lo que estoy tratando de hacer. 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'));

Respuestas:


197

Puede usar this.props.childrenpara representar cualquier elemento secundario que contenga el componente:

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

export default () => <Wrap><h1>Hello word</h1></Wrap>

44
Yo usaría esta respuesta. this.props.childrenes parte de la API del componente y se espera que se use de esta manera. Los ejemplos del equipo React usan esta técnica, como en la transferencia de accesorios y cuando se habla de un solo niño .
Ross Allen

De mi comentario a continuación: al pasarlo como accesorio, incluso puede darle un nombre y usar propTypes para escribir check.
returnneax

1
@AndrewAllbright: Tu ejemplo no estaba pasando a ningún niño. Esto funciona: codepen.io/ssorallen/pen/Dyjmk
Ross Allen

Y en caso de que quiera obtener los nodos DOM de los niños: stackoverflow.com/questions/29568721/…
ericsoco

124

Tenga en cuenta que proporcioné una respuesta más detallada aquí

Contenedor de tiempo de ejecución:

Es la forma más idiomática.

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

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

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

Tenga en cuenta que childrenes un "accesorio especial" en React, y el ejemplo anterior es el azúcar sintáctico y es (casi) equivalente a<Wrapper children={<App/>}/>


Inicialización wrapper / HOC

Puede usar un Componente de orden superior (HOC). Se han agregado al documento oficial recientemente.

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

Esto puede conducir a (poco) mejores rendimientos porque el componente contenedor puede cortocircuitar la representación un paso adelante con shouldComponentUpdate, mientras que en el caso de un contenedor de tiempo de ejecución, es probable que el elemento secundario sea siempre un ReactElement diferente y cause renders incluso si sus componentes extienden PureComponent.

Tenga en cuenta que connectRedux solía ser un contenedor de tiempo de ejecución, pero se cambió a un HOC porque permite evitar representaciones inútiles si usa la pureopción (que es verdadera por defecto)

Nunca debe llamar a un HOC durante la fase de renderizado porque crear componentes React puede ser costoso. Debería llamar a estos contenedores en la inicialización.


Tenga en cuenta que cuando se usan componentes funcionales como los anteriores, la versión HOC no proporciona ninguna optimización útil porque los componentes funcionales sin estado no se implementan shouldComponentUpdate

Más explicaciones aquí: https://stackoverflow.com/a/31564812/82609


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

Esto hubiera sido correcto si fuera ... React 15.x no le permite devolver un componente de múltiples nodos. React 16 (también conocido como React Fiber) permitirá múltiples nodos. Aquí está la solución para su ejemplo de código: const ParentComponent = (props) => ({props.childComponent}); importar MyComponent desde //...where ever const myComponent = <MyComponent /> // pasar como prop <ParentComponent childComponent = {myComponent} />
Andrew Allbright

13

Facebook recomienda el uso de componentes sin estado Fuente: https://facebook.github.io/react/docs/reusable-components.html

En un mundo ideal, la mayoría de sus componentes serían funciones sin estado porque en el futuro también podremos realizar optimizaciones de rendimiento específicas para estos componentes evitando verificaciones innecesarias y asignaciones de memoria. Este es el patrón recomendado, cuando sea posible.

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

13

Puedes pasarlo como un accesorio normal: foo={<ComponentOne />}

Por ejemplo:

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

9

prefiero usar React API incorporada:

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

entonces puedes reemplazar el wrapper div con lo que quieras:

<Test wrapper={<span className="LOL"/>}>
  <div>child1</div>
  <div>child2</div>
</Test> 

5

Puede pasar un componente a través de. los accesorios y renderizarlo con interpolación.

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

Luego pasaría un propllamado child, que sería un componente Reaccionar.


1
Esto llevaría a pasar componentes a través de atributos en lugar de como hijos. Si usa this.props.childrencomo se sugiere en otra respuesta, puede escribir a los niños como niños en lugar de atributos.
Ross Allen

1
@ssorallen no dijiste por qué uno es mejor de ninguna manera ... Al pasarlo como accesorio, incluso puedes darle un nombre y usar propTypes para escribir check.
returnneax

1
Cada elemento que usa en JSX es solo un componente. Si usaran este enfoque, no podría escribir ni siquiera su breve ejemplo. Se convertiría <div child={this.props.child />.
Ross Allen

1
Consulte la versión de JavaScript (en lo que JSX lo convierte): jsfiddle.net/ssorallen/kvrxcqv8/2 . React.DOM.div, como todos los componentes principales, utiliza la childrenmatriz. Mire cómo se usa en su Hellocomponente, ya está usando varios hijos.
Ross Allen el

20
La desventaja de continuar una discusión en el chat es que no se archivan para futuros lectores.
ultrafez

3

Al final del juego, pero aquí hay un poderoso patrón HOC para anular un componente al proporcionarlo como accesorio. Es simple y elegante.

Suponga que MyComponentrepresenta un Acomponente ficticio pero desea permitir una anulación personalizada de A, en este ejemplo B, que se ajusta Aen <div>...</div>ay también agrega "!" al texto prop:

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

1

En realidad, su pregunta es cómo escribir un Componente de orden superior (HOC). El objetivo principal de usar HOC es evitar el pegado de copias. Puede escribir su HOC como un componente puramente funcional o como una clase. Aquí hay un ejemplo:

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

Si desea escribir su componente principal como un componente basado en la clase:

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

Si desea escribir a su padre como un componente funcional:

    const Parent=props=>{
    return(
        <div>
            {props.children}
        </div>
    )
}

0

Aquí hay un ejemplo de un componente de reacción Lista principal y cuyos accesorios contienen un elemento de reacción. En este caso, solo se pasa un solo componente de reacción de Enlace (como se ve en el render 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')
);

0

Sí, puede hacerlo utilizando accesorios, puede pasar datos del componente como un objeto como accesorios y luego dentro del componente puede importar otro componente y enlazar dinámicamente con datos de prpps. lea más sobre el componente reaccionar


1
¿Puedes elaborar algún código del enlace que publicaste?
Nelles
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.