Como passar adereços para {this.props.children}


889

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

<Parent>
  <Child value="1">
  <Child value="2">
</Parent>

Existe uma lógica em andamento para renderização entre componentes pai e filho, é claro, você pode imaginar <select>e <option>como um exemplo dessa lógica.

Esta é uma implementação fictícia para o objetivo da pergunta:

var Parent = React.createClass({
  doSomething: function(value) {
  },
  render: function() {
    return (<div>{this.props.children}</div>);
  }
});

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

A pergunta é sempre que você usa {this.props.children}para definir um componente de wrapper, como você transmite alguma propriedade para todos os seus filhos?


Respostas:


955

Clonando crianças com novos adereços

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

import React, { Children, isValidElement, cloneElement } from 'react';

const Child = ({ doSomething, value }) => (
  <div onClick={() => doSomething(value)}>Click Me</div>
);

function Parent({ children }) {
  function doSomething(value) {
    console.log('doSomething called by child with value:', value);
  }

  render() {
    const childrenWithProps = Children.map(children, child => {
      // Checking isValidElement is the safe way and avoids a TS error too.
      if (isValidElement(child)) {
        return cloneElement(child, { doSomething })
      }

      return child;
    });

    return <div>{childrenWithProps}</div>
  }
};

ReactDOM.render(
  <Parent>
    <Child value="1" />
    <Child value="2" />
  </Parent>,
  document.getElementById('container')
);

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

Chamando crianças como uma função

Você também pode passar adereços para crianças com adereços de renderização . Nesta abordagem, os filhos (que podem ser childrenou qualquer outro nome de prop) são uma função que pode aceitar todos os argumentos que você deseja passar e retorna os filhos:

const Child = ({ doSomething, value }) => (
  <div onClick={() =>  doSomething(value)}>Click Me</div>
);

function Parent({ children }) {
  function doSomething(value) {
    console.log('doSomething called by child with value:', value);
  }

  render() {
    // Note that children is called as a function and we can pass args to it
    return <div>{children(doSomething)}</div>
  }
};

ReactDOM.render(
  <Parent>
    {doSomething => (
      <React.Fragment>
        <Child doSomething={doSomething} value="1" />
        <Child doSomething={doSomething} value="2" />
      </React.Fragment>
    )}
  </Parent>,
  document.getElementById('container')
);

Em vez de <React.Fragment>ou simplesmente, <>você também pode retornar uma matriz, se preferir.

Fiddle: https://jsfiddle.net/ferahl/y5pcua68/7/


7
Isso não funciona para mim. isso não é definido dentro React.cloneElement ()
Patrick

12
Esta resposta não funciona, o valuepassado para doSomethingé perdido.
Dave

3
@DominicTobias Arg, desculpe, mudei console.log para alertar e esqueci de concatinar os dois parâmetros em uma única string.
Dave

1
Essa resposta foi super útil, mas me deparei com um problema que não foi mencionado aqui e fiquei me perguntando se alguma coisa nova mudou ou se é algo estranho da minha parte. Quando clonei meu elemento filho, seu filho foi definido como o elemento antigo, até eu adicionar this.props.children.props.children ao terceiro argumento de cloneElement.
aphenine

7
E se o filho for carregado por uma rota (v4) carregada de uma página de rota separada?
blamb

394

Para uma maneira um pouco mais limpa, tente:

<div>
    {React.cloneElement(this.props.children, { loggedIn: this.state.loggedIn })}
</div>

Editar: Para usar com vários filhos individuais (o filho deve ser um componente), você pode fazer. Testado em 16.8.6

<div>
    {React.cloneElement(props.children[0], { loggedIn: true, testingTwo: true })}
    {React.cloneElement(props.children[1], { loggedIn: true, testProp: false })}
</div>

10
Eu estava usando a resposta mais votada, mas essa é muito mais direta! Essa solução também é o que eles usam na página de exemplos do reag-router.
Capt # Day16

10
Alguém poderia explicar como isso funciona (ou o que realmente faz)? Lendo os documentos , eu não conseguia ver como isso iria se infiltrar nas crianças e adicionar esse suporte a cada criança - é isso que ela pretende fazer? Se sim, como sabemos que é isso que fará? Não é de todo óbvio que seja válido passar uma estrutura de dados opaca ( this.props.children) para cloneElement... que está esperando um ... elemento.
GreenAsJade

51
Exatamente, isso não parece funcionar com mais de um filho.
Danita 29/03

17
Então, você pode escrever um código que funcione enquanto alguém passa apenas um filho em um componente, mas quando ele adiciona outro, ele trava ... isso não soa muito bem no valor nominal? Parece ser uma armadilha para o OP, que perguntou especificamente sobre a passagem de adereços para todas as crianças.
GreenAsJade 5/05

10
O @GreenAsJade está bom desde que seu componente esteja esperando um único filho. Você pode definir, através de seus componentes, propTypes que espera um único filho. React.Children.onlyA função retorna o único filho ou lança uma exceção se houver vários (isso não existiria se não houvesse um caso de uso).
Cchamberlain

80

Tente isto

<div>{React.cloneElement(this.props.children, {...this.props})}</div>

Funcionou para mim usando o react-15.1.


3
É possível retornar React.cloneElement()diretamente sem colocá-lo em <div>tags? Porque e se a criança for <span>(ou outra coisa) e quisermos preservar seu tipo de elemento de tag?
precisa

1
Se for um filho, você pode deixar de fora o invólucro e esta solução funciona apenas para um filho, então sim.
ThaJay

1
Funciona para mim. Sem incluir <div> está ok.
Crash Override

4
Se você precisar fazer cumprir explicitamente que recebe apenas um filho, poderá executar React.cloneElement(React.Children.only(this.props.children), {...this.props})um erro que passará mais de um filho. Então você não precisa agrupar uma div.
itsananderson

1
Esta resposta pode produzir um valor de objeto cíclico TypeError:. A menos que você queira que um dos objetos da criança seja ele mesmo, use let {children, ...acyclicalProps} = this.propse então React.cloneElement(React.Children.only(children), acyclicalProps).
Parabolord

69

Passe adereços para direcionar as crianças.

Veja todas as outras respostas

Passe dados globais compartilhados pela árvore de componentes via contexto

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

Isenção de responsabilidade: esta é uma resposta atualizada, a anterior usou a API de contexto antiga

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

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

Em seguida, use via

<Provider value={/* some value */}>
  {children} /* potential consumers */
<Provider />

e

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

Todos os Consumidores descendentes de um Fornecedor serão renderizados novamente sempre que o valor do fornecedor for alterado. A propagação do Provedor para seus Consumidores descendentes não está sujeita ao método shouldComponentUpdate, portanto, o Consumidor é atualizado mesmo quando um componente ancestral fica fora 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 (
      <Provider value={this.state.value}>
        <Toolbar />
      </Provider>
    );
  }
}

class Toolbar extends React.Component {
  render() {
    return ( 
      <div>
        <p> Consumer can be arbitrary levels deep </p>
        <Consumer> 
          {value => <p> The toolbar will be in color {value.color} </p>}
        </Consumer>
      </div>
    );
  }
}

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


6
Diferentemente da resposta aceita, isso funcionará corretamente, mesmo quando houver outros elementos incluídos no Parent. Esta é definitivamente a melhor resposta.
Zaptree

6
! Props = contexto
Petr Peller

você não pode depender das mudanças que se propagam pelo contexto. Use adereços quando for possível que eles mudem.
ThaJay

1
Talvez eu não entenda, mas não é errado dizer "o contexto disponibiliza adereços"? Quando usei o contexto pela última vez, era uma coisa separada (ie this.context) - não magicamente mesclava o contexto com adereços. Você tinha que intencionalmente definir e usar o contexto, o que é uma coisa totalmente diferente.
21417 Josh

Você entende perfeitamente, estava incorreto. Eu editei minha resposta.
precisa

48

Passando adereços para crianças aninhadas

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

import * as React from 'react';

// React.createContext accepts a defaultValue as the first param
const MyContext = React.createContext(); 

class Parent extends React.Component {
  doSomething = (value) => {
    // Do something here with value
  };

  render() {
    return (
       <MyContext.Provider value={{ doSomething: this.doSomething }}>
         {this.props.children}
       </MyContext.Provider>
    );
  }
}

class Child extends React.Component {
  static contextType = MyContext;

  onClick = () => {
    this.context.doSomething(this.props.value);
  };      

  render() {
    return (
      <div onClick={this.onClick}>{this.props.value}</div>
    );
  }
}


// Example of using Parent and Child

import * as React from 'react';

class SomeComponent extends React.Component {

  render() {
    return (
      <Parent>
        <Child value={1} />
        <Child value={2} />
      </Parent>
    );
  }
}

React.createContext brilha onde o caso React.cloneElement não pode manipular componentes aninhados

class SomeComponent extends React.Component {

  render() {
    return (
      <Parent>
        <Child value={1} />
        <SomeOtherComp><Child value={2} /></SomeOtherComp>
      </Parent>
    );
  }
}

3
Você pode explicar por que = = funções são uma má prática? A função => ajuda ligam os manipuladores de eventos para obter thiscontexto
Kenneth Truong

@KennethTruong, porque cada vez que processa, cria uma função.
itdoesntwork

9
@itdoesntwork isso não é verdade. Ele só cria uma nova função quando a classe é criada. Não está sendo criado durante a função de renderização ..
Kenneth Truong

@KennethTruong reactjs.org/docs/faq-functions.html#arrow-function-in-render Eu pensei que você estava falando sobre a função de seta no render.
itdoesntwork

24

Você pode usar React.cloneElement, é melhor saber como funciona antes de começar a usá-lo em seu aplicativo. É introduzido React v0.13, continue a ler para obter mais informações; portanto, algo junto com este trabalho para você:

<div>{React.cloneElement(this.props.children, {...this.props})}</div>

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

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

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

Diferentemente de cloneWithProps, essa nova função não possui nenhum comportamento mágico incorporado para mesclar estilo e className pelo mesmo motivo pelo qual não temos esse recurso de transferPropsTo. Ninguém sabe ao certo qual é exatamente a lista completa de coisas mágicas, o que dificulta o raciocínio sobre o código e a reutilização quando o estilo tem uma assinatura diferente (por exemplo, no próximo React Native).

React.cloneElement é quase equivalente a:

<element.type {...element.props} {...props}>{children}</element.type>

No entanto, diferentemente do JSX e do cloneWithProps, ele também preserva refs. Isso significa que, se você conseguir um filho com um juiz, não o roubará acidentalmente do seu antepassado. Você receberá a mesma referência anexada ao seu novo elemento.

Um padrão comum é mapear seus filhos e adicionar um novo suporte. Houve muitos problemas relatados sobre cloneWithProps perdendo a ref, dificultando o raciocínio sobre seu código. Agora, seguir 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 a ref, portanto ainda não é possível que dois pais tenham uma ref para o mesmo filho, a menos que você use callback-refs.

Esse foi um recurso crítico para entrar no React 0.13, pois os objetos agora são imutáveis. O caminho de atualização geralmente é para clonar o elemento, mas, ao fazer isso, você pode perder a referência. Portanto, precisávamos de um caminho de atualização melhor aqui. Ao atualizar os callites no Facebook, percebemos que precisávamos desse método. Recebemos o mesmo feedback da comunidade. Por isso, decidimos fazer outro RC antes do lançamento final para garantir isso.

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

mais aqui ...


18

A melhor maneira, que permite fazer a transferência de propriedade, é children como uma função

Exemplo:

export const GrantParent = () => {
  return (
    <Parent>
      {props => (
        <ChildComponent {...props}>
          Bla-bla-bla
        </ChildComponent>
      )}
    </Parent>
  )
}

export const Parent = ({ children }) => {
    const somePropsHere = { //...any }
    <>
        {children(somePropsHere)}
    </>
}

1
Isso me parece muito mais direto (e melhor para o desempenho?) Do que a resposta aceita.
Shikyo 3/03/19

2
Isso requer que as crianças ser uma função e não funciona para componentes deply aninhados
ilusão digital de

@digitalillusion, eu não entendo o que isso significa nested components. React não possui padrões aninhados, apenas composições. Sim, os filhos devem ser uma função, não há conflitos, porque esse é o filho JSX válido. Você pode dar um exemplo com nesting components?
Nick Ovchinnikov

1
Você está certo no caso das crianças profundamente aninhados podem ser tratadas assim <Parent>{props => <Nest><ChildComponent /></Nest>}</Parent>, em vez de (não funciona) <Parent><Nest>{props => <ChildComponent />}</Nest></Parent>, então eu concordo que isso é a melhor resposta
ilusão digital de

Ao tentar, recebo o seguinte:TypeError: children is not a function
Ryan Prentiss

6

Eu precisava corrigir a resposta aceita acima para fazê-la funcionar usando isso em vez deste ponteiro. Isso no escopo da função map não tinha a função 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 <div>{childrenWithProps}</div>
}})

Atualização: essa correção é para o ECMAScript 5, no ES6 não é necessário var que = isto


13
ou apenas usebind()
mais-

1
ou usar uma função seta que se liga ao escopo léxico, eu atualizei a minha resposta
Dominic

o que se doSomethingtomou um objeto, como doSomething: function(obj) { console.log(obj) }e no Menino você chamaria this.props.doSomething(obj)para fazer logout"obj"
conor909

4
@ plus- eu sei que isso é antigo, mas usar bind aqui é uma péssima idéia, bind cria uma nova função que liga o contexto a uma nova. basicamente uma função chamando o applymétodo O uso bind()da função de renderização criará uma nova função sempre que o método de renderização for chamado.
Bamieh

6

Maneira mais limpa considerando um ou mais filhos

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

Este não funciona para mim, dá um erro: filhos não definidos.
Deelux

@Deelux this.props.children em vez de crianças
Martin Dawson

isso passa a criança como seus próprios filhos this.props. Em geral, eu recomendaria apenas a clonagem com adereços específicos, e não o shebang inteiro.
Andy

Passar {...this.props}não funcionou para mim, é o caminho {...child.props}correto?
Felipe Augusto

Para componentes funcionais:React.Children.map(children, child => React.cloneElement(child, props))
vsync

5

Nenhuma das respostas aborda a questão de ter filhos que não são componentes do React, como seqüências de caracteres de texto. Uma solução alternativa pode ser algo como isto:

// 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 <div>{childrenWithProps}</div>

}

5

Você não precisa mais {this.props.children}. Agora você pode agrupar o componente filho usando renderin Routee passar seus adereços como de costume:

<BrowserRouter>
  <div>
    <ul>
      <li><Link to="/">Home</Link></li>
      <li><Link to="/posts">Posts</Link></li>
      <li><Link to="/about">About</Link></li>
    </ul>

    <hr/>

    <Route path="/" exact component={Home} />
    <Route path="/posts" render={() => (
      <Posts
        value1={1}
        value2={2}
        data={this.state.data}
      />
    )} />
    <Route path="/about" component={About} />
  </div>
</BrowserRouter>

2
Agora, os objetos de renderização são padrão no React ( reactjs.org/docs/render-props.html ) e vale a pena considerar como uma nova resposta aceita para esta pergunta.
18718 Ian

19
Como isso é uma resposta para a pergunta?
Maximo Dominguez

4

Parent.jsx:

import React from 'react';

const doSomething = value => {};

const Parent = props => (
  <div>
    {
      !props || !props.children 
        ? <div>Loading... (required at least one child)</div>
        : !props.children.length 
            ? <props.children.type {...props.children.props} doSomething={doSomething} {...props}>{props.children}</props.children.type>
            : props.children.map((child, key) => 
              React.cloneElement(child, {...props, key, doSomething}))
    }
  </div>
);

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 }) => (
  <div onClick={() => doSomething(value)}/>
);

e main.jsx:

import React from 'react';
import { render } from 'react-dom';
import Parent from './Parent';
import Child from './Child';

render(
  <Parent>
    <Child/>
    <Child value='1'/>
    <Child value='2'/>
  </Parent>,
  document.getElementById('...')
);

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



4

Se você tem vários filhos aos quais deseja passar adereços , pode fazê-lo desta maneira, usando o mapa React.Children.map:

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

    return (
        <div>
            { updatedChildren }
        </div>
    );
}

Se o seu componente está tendo apenas um filho, não há necessidade de mapeamento, basta clonar o elemento imediatamente:

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

3

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

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

Clone e retorne um novo elemento React usando o elemento como ponto de partida. O elemento resultante terá os adereços do elemento original com os novos adereços mesclados superficialmente. Novos filhos substituirão os existentes. key e ref do elemento original serão preservados.

React.cloneElement() é quase equivalente a:

<element.type {...element.props} {...props}>{children}</element.type>

No entanto, também preserva refs. Isso significa que, se você conseguir um filho com um juiz, não o roubará acidentalmente do seu antepassado. Você receberá a mesma referência anexada ao seu novo elemento.

Portanto, cloneElement é o que você usaria para fornecer adereços personalizados para os filhos. No entanto, pode haver vários filhos no componente e você precisará fazer um loop sobre ele. O que outras respostas sugerem é que você as mapeie usando React.Children.map. No entanto, React.Children.mapao contrário das React.cloneElementalterações, as teclas do elemento anexado e extra .$como prefixo. Verifique esta pergunta para obter mais detalhes: React.cloneElement dentro de React.Children.map está causando alterações nas chaves dos elementos

Se você deseja evitá-lo, deve executar a forEachfunção como

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

}

2

Além da resposta @and_rest, é assim que clono as crianças e adiciono uma classe.

<div className="parent">
    {React.Children.map(this.props.children, child => React.cloneElement(child, {className:'child'}))}
</div>

2

Eu acho que um suporte de renderização é a maneira apropriada de lidar com esse cenário

Você permite que o pai forneça os adereços necessários usados ​​no componente filho, refatorando o código pai para se parecer com algo assim:

const Parent = ({children}) => {
  const doSomething(value) => {}

  return children({ doSomething })
}

Em seguida, no componente filho, você pode acessar a função fornecida pelo pai desta maneira:

class Child extends React {

  onClick() => { this.props.doSomething }

  render() { 
    return (<div onClick={this.onClick}></div>);
  }

}

Agora a estrutura do noivo ficará assim:

<Parent>
  {(doSomething) =>
   (<Fragment>
     <Child value="1" doSomething={doSomething}>
     <Child value="2" doSomething={doSomething}>
    <Fragment />
   )}
</Parent>

e se o pai for apenas um invólucro para um {filho} que é uma área de texto em outro componente da classe?
Adebayo

2

Método 1 - clonar crianças

const Parent = (props) => {
   const attributeToAddOrReplace= "Some Value"
   const childrenWithAdjustedProps = React.Children.map(props.children, child =>
      React.cloneElement(child, { attributeToAddOrReplace})
   );

   return <div>{childrenWithAdjustedProps }</div>
}

Método 2 - usar contexto compositável

O contexto permite que você transmita um suporte a um componente filho profundo sem transmiti-lo explicitamente como um suporte pelos componentes intermediários.

O contexto vem com desvantagens:

  1. Os dados não fluem da maneira regular - via adereços.
  2. Usar o contexto cria um contrato entre o consumidor e o provedor. Pode ser mais difícil entender e replicar os requisitos necessários para reutilizar um componente.

Usando um contexto compositável

export const Context = createContext<any>(null);

export const ComposableContext = ({ children, ...otherProps }:{children:ReactNode, [x:string]:any}) => {
    const context = useContext(Context)
    return(
      <Context.Provider {...context} value={{...context, ...otherProps}}>{children}</Context.Provider>
    );
}

function App() {
  return (
      <Provider1>
            <Provider2> 
                <Displayer />
            </Provider2>
      </Provider1>
  );
}

const Provider1 =({children}:{children:ReactNode}) => (
    <ComposableContext greeting="Hello">{children}</ComposableContext>
)

const Provider2 =({children}:{children:ReactNode}) => (
    <ComposableContext name="world">{children}</ComposableContext>
)

const Displayer = () => {
  const context = useContext(Context);
  return <div>{context.greeting}, {context.name}</div>;
};

Um pouco tarde, mas você poderia explicar a notação {children}:{children:ReactNode}?
camille

@camille, é uma coisa datilografada. Olhando para ele agora, eu responderia apenas com Javascript e, mesmo que escrevesse Typescript, faria diferente. Pode editá-lo no futuro.
Ben Carp

1
@camille, basicamente significa que o valor que possui a chave "children"é do tipoReactNode
Ben Carp

1

A maneira mais eficiente de fazer isso:

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

5
Isso não copia this.props.children para this.props.children da criança? e, com efeito, copiar a criança para si mesma?
Arshabh Agarwal 10/09/16

1

Para qualquer pessoa que tenha um único elemento filho, isso deve ser feito.

{React.isValidElement(this.props.children)
                  ? React.cloneElement(this.props.children, {
                      ...prop_you_want_to_pass
                    })
                  : null}

0

É isso que você precisa?

var Parent = React.createClass({
  doSomething: function(value) {
  }
  render: function() {
    return  <div>
              <Child doSome={this.doSomething} />
            </div>
  }
})

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

4
Não, não quero restringir o conteúdo do meu wrapper para algum conteúdo específico.
mais-

0

Por alguma razão, o React.children não estava trabalhando para mim. Isto é o que funcionou para mim.

Eu queria apenas adicionar uma classe à criança. semelhante a alterar um suporte

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

 return <div>{newChildren}</div>;

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


0

Render adereços é a abordagem mais precisa para esse problema. Em vez de passar o componente filho para o componente pai como adereços filhos, deixe o pai renderizar o componente filho manualmente. Render é adereços embutidos no react, que recebe o parâmetro de função. Nesta função, você pode deixar o componente pai renderizar o que quiser com parâmetros personalizados. Basicamente, faz o mesmo que adereços filhos, mas é mais personalizável.

class Child extends React.Component {
  render() {
    return <div className="Child">
      Child
      <p onClick={this.props.doSomething}>Click me</p>
           {this.props.a}
    </div>;
  }
}

class Parent extends React.Component {
  doSomething(){
   alert("Parent talks"); 
  }

  render() {
    return <div className="Parent">
      Parent
      {this.props.render({
        anythingToPassChildren:1, 
        doSomething: this.doSomething})}
    </div>;
  }
}

class Application extends React.Component {
  render() {
    return <div>
      <Parent render={
          props => <Child {...props} />
        }/>
    </div>;
  }
}

Exemplo no codepen


0

Ao usar componentes funcionais, você geralmente recebe o TypeError: Cannot add property myNewProp, object is not extensibleerro ao tentar definir novas propriedades props.children. Existe uma solução para isso clonando os adereços e depois a criança com os novos adereços.

const MyParentComponent = (props) => {
  return (
    <div className='whatever'>
      {props.children.map((child) => {
        const newProps = { ...child.props }
        // set new props here on newProps
        newProps.myNewProp = 'something'
        const preparedChild = { ...child, props: newProps }
        return preparedChild
      })}
    </div>
  )
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.