Como passar props para {this.props.children}

Estou tentando encontrar a maneira correta de definir alguns componentes que poderiam ser usados ​​de maneira genérica:

    

Há uma lógica em andamento para renderização entre os componentes pai e filho, é claro, você pode imaginar e como um exemplo dessa lógica.

Esta é uma implementação fictícia para o propósito da questão:

 var Parent = React.createClass({ doSomething: function(value) { }, render: function() { return (
{this.props.children}
); } }); var Child = React.createClass({ onClick: function() { this.props.doSomething(this.props.value); // doSomething is undefined }, render: function() { return (
); } });

A questão é sempre que você usa {this.props.children} para definir um componente wrapper, como você passa uma propriedade para todos os seus filhos?

Você pode usar React.Children para iterar sobre os filhos e, em seguida, clonar cada elemento com novos adereços ( mesclagem superficial) usando React.cloneElement, por exemplo:

 const Child = ({ doSomething, value }) => ( 
doSomething(value)}>Click Me
); class Parent extends React.PureComponent { doSomething = (value) => { console.log('doSomething called by child with value:', value); } render() { const { children } = this.props; const childrenWithProps = React.Children.map(children, child => React.cloneElement(child, { doSomething: this.doSomething })); return
{childrenWithProps}
} }; ReactDOM.render( , document.getElementById('container') );

Violino: https://jsfiddle.net/2q294y43/2/

Para uma maneira um pouco mais limpa de fazer isso, tente:

 
{React.cloneElement(this.props.children, { loggedIn: this.state.loggedIn })}

Nota : isso só funcionará se houver um único filho e for um elemento React válido.

Tente isso

 
{React.cloneElement(this.props.children, {...this.props})}

Funcionou para mim usando reagir-15.1.

Passe adereços para direcionar as crianças.

Veja todas as outras respostas

Passar dados globais compartilhados através da tree de componentes via contexto

O contexto é projetado para compartilhar dados que podem ser considerados “globais” para uma tree de componentes do React, como o usuário autenticado atual, o tema ou o idioma preferencial. 1

Aviso: esta é uma resposta atualizada, a anterior usou a antiga API de contexto

É baseado no princípio do Consumidor / Provide. Primeiro, crie seu contexto

 const { Provider, Consumer } = React.createContext(defaultValue); 

Então use via

  {children} /* potential consumers */  

e

  {value => /* render something based on the context value */}  

Todos os Consumidores que são descendentes de um Provedor serão renderizados novamente sempre que o valor do Provedor for alterado. A propagação do Provedor para seu Consumidor descendente não está sujeita ao método shouldComponentUpdate, portanto, o Consumidor é atualizado mesmo quando um componente de ancestral é excluído da atualização. 1

Exemplo completo, semi-pseudo código.

 import React from 'react'; const { Provider, Consumer } = React.createContext({ color: 'white' }); class App extends React.Component { constructor(props) { super(props); this.state = { value: { color: 'black' }, }; } render() { return (    ); } } class Toolbar extends React.Component { render() { return ( 

Consumer can be arbitrary levels deep

{value =>

The toolbar will be in color {value.color}

}
); } }

1 https://facebook.github.io/react/docs/context.html

Você pode usar o React.cloneElement , é melhor saber como funciona antes de começar a usá-lo em seu aplicativo. É introduzido no React v0.13 , continue lendo para mais informações, então algo junto com esse trabalho para você:

 
{React.cloneElement(this.props.children, {...this.props})}

Então, traga as linhas da documentação do React para você entender como tudo está funcionando e como você pode usá-las:

No React v0.13 RC2, introduziremos uma nova API, semelhante a React.addons.cloneWithProps, com esta assinatura:

 React.cloneElement(element, props, ...children); 

Ao contrário de cloneWithProps, essa nova function não possui nenhum comportamento interno mágico para mesclar estilo e className pelo mesmo motivo pelo qual não temos esse recurso de transferPropsTo. Ninguém tem certeza do que exatamente é a lista completa de coisas mágicas, o que torna difícil raciocinar sobre o código e é difícil reutilizá-lo quando o estilo tiver uma assinatura diferente (por exemplo, no próximo React Native).

React.cloneElement é quase equivalente a:

 {children} 

No entanto, ao contrário de JSX e cloneWithProps, ele também preserva os refs. Isso significa que, se você receber uma criança com uma referência, você não a roubará acidentalmente do seu antepassado. Você receberá o mesmo ref anexado ao seu novo elemento.

Um padrão comum é mapear seus filhos e adicionar um novo adereço. Houve muitos problemas relatados sobre cloneWithProps perder o ref, tornando mais difícil raciocinar sobre o seu código. Agora seguindo o mesmo padrão com cloneElement funcionará como esperado. Por exemplo:

 var newChildren = React.Children.map(this.props.children, function(child) { return React.cloneElement(child, { foo: true }) }); 

Nota: React.cloneElement (child, {ref: ‘newRef’}) SUBSTITUI o ref, então ainda não é possível para dois pais terem um ref no mesmo filho, a menos que você use callback-refs.

Esta foi uma característica crítica para entrar no React 0.13, já que os suportes agora são imutáveis. O caminho de atualização geralmente é para clonar o elemento, mas, ao fazer isso, você pode perder o ref. Portanto, precisávamos de um melhor caminho de atualização aqui. Enquanto atualizávamos os sites de chamadas no Facebook, percebemos que precisávamos desse método. Nós recebemos o mesmo feedback da comunidade. Por isso, decidimos fazer outro RC antes do lançamento final para nos certificarmos disso.

Planejamos eventualmente descontinuar React.addons.cloneWithProps. Ainda não estamos fazendo isso, mas essa é uma boa oportunidade para começar a pensar em seus próprios usos e considerar o uso de React.cloneElement. Iremos enviar uma versão com avisos de descontinuação antes de removê-la, de modo que nenhuma ação imediata seja necessária.

mais aqui …

Com a atualização para o React 16.3, agora você pode usar o React.createContext .

 import * as React from 'react'; // React.createContext accepts a defaultValue as the first param const { Provider: ParentProvider, Consumer: ChildConsumer } = React.createContext(); class Parent extends React.Component { doSomething = (value) => { // Do something here with value }; render() { return (  {this.props.children}  ); } } class Child extends React.Component { render() { const { value } = this.props; return (  (({ doSomething }) => { return 
doSomething(value)}>{value}
})
); } } // Example of using Parent and Child import * as React from 'react'; class SomeComponent extends React.Component { render() { } }

React.createContext brilha onde o caso React.cloneElement não pôde manipular componentes nesteds

 class SomeComponent extends React.Component { render() {     } } 

Eu precisava consertar a resposta acima para fazê-la funcionar usando isso em vez desse ponteiro. Isso dentro do escopo da function map não tem a function do doSomething definida.

 var Parent = React.createClass({ doSomething: function() { console.log('doSomething!'); }, render: function() { var that = this; var childrenWithProps = React.Children.map(this.props.children, function(child) { return React.cloneElement(child, { doSomething: that.doSomething }); }); return 
{childrenWithProps}
}})

Update: esta correção é para ECMAScript 5, no ES6 não há necessidade em var que = this

Maneira mais limpa, considerando um ou mais filhos

 
{ React.Children.map(this.props.children, child => React.cloneElement(child, {...this.props}))}

Você não precisa mais de {this.props.children} . Agora você pode envolver seu componente filho usando render no Route e passar seus props como de costume:

  
  • Home
  • Posts
  • About

( )} />

Nenhuma das respostas resolve o problema de ter filhos que NÃO são componentes React, como strings de texto. Uma solução alternativa poderia ser algo assim:

 // Render method of Parent component render(){ let props = { setAlert : () => {alert("It works")} }; let childrenWithProps = React.Children.map( this.props.children, function(child) { if (React.isValidElement(child)){ return React.cloneElement(child, props); } return child; }); return 
{childrenWithProps}
}

Se você tem vários filhos para os quais deseja passar , você pode fazer isso usando o React.Children.map:

 render() { let updatedChildren = React.Children.map(this.props.children, (child) => { return React.cloneElement(child, { newProp: newProp }); }); return ( 
{ updatedChildren }
); }

Se o seu componente está tendo apenas um filho, não há necessidade de mapeamento, você pode simplesmente clonarElement imediatamente:

 render() { return ( 
{ React.cloneElement(this.props.children, { newProp: newProp }) }
); }

Além da resposta @and_rest, é assim que eu clono os filhos e adiciono uma turma.

 
{React.Children.map(this.props.children, child => React.cloneElement(child, {className:'child'}))}

Parent.jsx:

 import React from 'react'; const doSomething = value => {}; const Parent = props => ( 
{ !props || !props.children ?
Loading... (required at least one child)
: !props.children.length ? {props.children} : props.children.map((child, key) => React.cloneElement(child, {...props, key, doSomething})) }
);

Child.jsx:

 import React from 'react'; /* but better import doSomething right here, or use some flux store (for example redux library) */ export default ({ doSomething, value }) => ( 
doSomething(value)}/> );

e main.jsx:

 import React from 'react'; import { render } from 'react-dom'; import Parent from './Parent'; import Child from './Child'; render(     , document.getElementById('...') ); 

veja o exemplo aqui: https://plnkr.co/edit/jJHQECrKRrtKlKYRpIWl?p=preview

De acordo com a documentação do cloneElement()

 React.cloneElement( element, [props], [...children] ) 

Clone e retorne um novo elemento React usando element como ponto de partida. O elemento resultante terá os elementos do elemento original com os novos suportes mesclados superficialmente. Novas crianças replaceão as crianças existentes. key e ref do elemento original serão preservados.

React.cloneElement() é quase equivalente a:

 {children} 

No entanto, também preserva refs. Isso significa que, se você receber uma criança com uma referência, você não a roubará acidentalmente do seu antepassado. Você receberá o mesmo ref anexado ao seu novo elemento.

Então cloneElement é o que você usaria para fornecer adereços personalizados para as crianças. No entanto, pode haver vários filhos no componente e você precisará passar por cima dele. O que outras respostas sugerem é que você mapeie sobre elas usando React.Children.map . No entanto React.Children.map ao contrário de React.cloneElement altera as chaves do elemento anexando e extra .$ Como o prefixo. Verifique esta questão para obter mais detalhes: React.cloneElement dentro de React.Children.map está fazendo com que as chaves de elemento sejam alteradas

Se você quiser evitá-lo, você deve ir para a function forEach como

 render() { const newElements = []; React.Children.forEach(this.props.children, child => newElements.push( React.cloneElement( child, {...this.props, ...customProps} ) ) ) return ( 
{newElements}
) }

É isso que você exigiu?

 var Parent = React.createClass({ doSomething: function(value) { } render: function() { return 
} }) var Child = React.createClass({ onClick:function() { this.props.doSome(value); // doSomething is undefined }, render: function() { return
} })

A maneira mais engenhosa de fazer isso:

  {React.cloneElement(this.props.children, this.props)} 

Alguma razão React.children não estava funcionando para mim. Isto é o que funcionou para mim.

Eu queria apenas adicionar uma aula para a criança. semelhante a mudar um prop

  var newChildren = this.props.children.map((child) => { const className = "MenuTooltip-item " + child.props.className; return React.cloneElement(child, { className }); }); return 
{newChildren}
;

O truque aqui é o React.cloneElement . Você pode passar qualquer suporte de maneira semelhante

Talvez você também possa achar útil esse recurso, embora muitas pessoas considerem isso como um antipadrão que ainda pode ser usado se você souber o que está fazendo e projetar bem sua solução.

Função como componentes filho

Pode simplesmente ser feito como:

 interface PaginationItemProps extends React.HTMLProps { } const PaginationItem = (props: PaginationItemProps) => { return 
{props.children}
; } class Pagination extends React.Component { render() { return
CHILDREN RENDER
} }