Como passar um componente de reação para outro componente de reação para transcluir o conteúdo do primeiro componente?

215

Existe uma maneira de passar um componente para outro componente de reação? Desejo criar um componente de reação do modelo e passar outro componente de reação para transcluir esse conteúdo.

Edit: Aqui está um codepen reactJS ilustrando o que estou tentando fazer. 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
fonte

Respostas:

197

Você pode usar this.props.childrenpara renderizar quaisquer filhos que o componente contenha:

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

export default () => <Wrap><h1>Hello word</h1></Wrap>
David Hellsing
fonte
4
Eu usaria essa resposta. this.props.childrenfaz parte da API do componente e espera-se que seja usado dessa maneira. Os exemplos da equipe do React usam essa técnica, como na transferência de objetos e quando se fala de um único filho .
Ross Allen
Do meu comentário abaixo: Ao passá-lo como um suporte, você pode até dar um nome e usar propTypes para digitar check.
returneax 12/09
1
@AndrewAllbright: Seu exemplo não estava passando por nenhum filho. Isso funciona: codepen.io/ssorallen/pen/Dyjmk
Ross Allen
E caso você queira obter os nós DOM dos filhos: stackoverflow.com/questions/29568721/…
ericsoco
124

Observe que forneci uma resposta mais aprofundada aqui

Wrapper de tempo de execução:

É a maneira mais 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>
);

Observe que childrené um "suporte especial" no React, e o exemplo acima é açúcar sintático e é (quase) equivalente a<Wrapper children={<App/>}/>


Wrapper de inicialização / HOC

Você pode usar um componente de ordem superior (HOC). Eles foram adicionados ao documento oficial recentemente.

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

Isso pode levar a (pouco) melhores desempenhos, porque o componente do wrapper pode causar um curto-circuito na renderização um passo à frente com shouldComponentUpdate, enquanto no caso de um wrapper de tempo de execução, o prop filho provavelmente sempre será um ReactElement diferente e causará novas renderizações mesmo que seus componentes estendam o PureComponent.

Observe que o connectRedux costumava ser um wrapper de tempo de execução, mas foi alterado para um HOC, pois permite evitar novas renderizações inúteis se você usar a pureopção (o que é verdadeiro por padrão)

Você nunca deve chamar um HOC durante a fase de renderização, pois a criação de componentes do React pode ser cara. Você deve chamar esses wrappers na inicialização.


Observe que, ao usar componentes funcionais como acima, a versão HOC não fornece nenhuma otimização útil porque os componentes funcionais sem estado não implementam shouldComponentUpdate

Mais explicações aqui: https://stackoverflow.com/a/31564812/82609

Sebastien Lorber
fonte
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
fonte
Isso estaria correto se fosse ... O React 15.x não permite que você retorne um componente com vários nós. O React 16 (também conhecido como React Fiber) permitirá vários nós. Aqui está a correção para o seu exemplo de código: const ParentComponent = (props) => ({props.childComponent}); importação MyComponent de //...where sempre const myComponent = <MyComponent /> // passar como prop <ParentComponent childComponent = {myComponent} />
Andrew Allbright
13

O Facebook recomenda o uso de componentes sem estado Fonte: https://facebook.github.io/react/docs/reusable-components.html

Em um mundo ideal, a maioria dos seus componentes seriam funções sem estado, porque no futuro também poderemos fazer otimizações de desempenho específicas para esses componentes, evitando verificações e alocações de memória desnecessárias. Este é o padrão recomendado, quando possível.

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
fonte
13

Você pode passá-lo como um suporte normal: foo={<ComponentOne />}

Por exemplo:

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

eu prefiro usar a API interna do 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
};

então você pode substituir a div do wrapper pelo que você quiser:

<Test wrapper={<span className="LOL"/>}>
  <div>child1</div>
  <div>child2</div>
</Test> 
Alnamrouti com tarifa
fonte
5

Você pode passar um componente via. os adereços e renderizá-lo com interpolação.

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

Você passaria uma propchamada child, que seria um componente React.

returneax
fonte
1
Isso levaria à passagem de componentes por atributos, e não como filhos. Se você usar this.props.childrencomo sugerido em outra resposta, poderá escrever os filhos como filhos em vez de attrs.
Ross Allen
1
@ssorallen, você não disse por que alguém é melhor de alguma forma ... Ao passá-lo como um suporte, você pode até dar um nome e usar propTypes para digitar check.
returneax 12/09
1
Cada elemento que você usa no JSX é apenas um componente. Se eles usassem essa abordagem, você não seria capaz de escrever nem um pequeno exemplo. Isso se tornaria <div child={this.props.child />.
Ross Allen
1
Confira a versão do JavaScript (na qual o JSX a transforma): jsfiddle.net/ssorallen/kvrxcqv8/2 . React.DOM.div, como todos os componentes principais, usa a childrenmatriz. Veja como ele é usado no seu Hellocomponente, ele já está usando vários filhos.
Ross Allen
20
A desvantagem de continuar uma discussão no bate-papo é que eles não são arquivados para futuros leitores.
ultrafez
3

Tarde do jogo, mas aqui está um poderoso padrão HOC para substituir um componente, fornecendo-o como um suporte. É simples e elegante.

Suponha que MyComponentrenderize um Acomponente fictício , mas você deseja permitir uma substituição personalizada de A, neste exemploB , que envolve Aum <div>...</div>e também anexa "!" para o 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}/>);
joneit
fonte
1

Na verdade, sua pergunta é como escrever um HOC (Higher Order Component). O principal objetivo do uso do HOC é impedir a cópia e colagem. Você pode escrever seu HOC como um componente puramente funcional ou como uma classe, aqui está um exemplo:

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

Se você deseja gravar seu componente pai como um componente baseado em classe:

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

Se você deseja escrever seu pai como um componente funcional:

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

Aqui está um exemplo de um componente de reação da lista pai e cujos adereços contêm um elemento de reação. Nesse caso, apenas um único componente de reação do Link é passado (como visto na renderização 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')
);
queijo
fonte
0

Sim, você pode fazê-lo usando adereços. Você pode passar dados do componente como um objeto, como adereços e, dentro do componente, pode importar outro componente e ligar dinamicamente aos dados do prpps. leia mais sobre o componente reagir

Dipankar Dutta
fonte
1
você pode elaborar com algum código do link que postou
Nelles 22/03