Come passare oggetti di scena a {this.props.children}


889

Sto cercando di trovare il modo corretto di definire alcuni componenti che potrebbero essere utilizzati in modo generico:

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

Esiste una logica in corso per il rendering tra componenti genitore e figlio, ovviamente, puoi immaginare <select>e <option>come esempio di questa logica.

Questa è un'implementazione fittizia ai fini della domanda:

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

La domanda è ogni volta che usi {this.props.children}per definire un componente wrapper, come passi una proprietà a tutti i suoi figli?


Risposte:


955

Clonare i bambini con nuovi oggetti di scena

Puoi usare React.Children per scorrere i bambini, quindi clonare ogni elemento con nuovi oggetti di scena (uniti in modo superficiale) usando React.cloneElement, ad esempio:

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/

Chiamare i bambini in funzione

Puoi anche passare oggetti di scena ai bambini con oggetti di rendering . In questo approccio i figli (che possono essere childreno qualsiasi altro nome di prop) è una funzione che può accettare qualsiasi argomento che si desidera passare e restituisce i figli:

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

Invece di <React.Fragment>o semplicemente <>puoi anche restituire un array se preferisci.

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


7
Questo non funziona per me. questo non è definito in React.cloneElement ()
Patrick

12
Questa risposta non funziona, il valuepassaggio a doSomethingè perso.
Dave

3
@DominicTobias Arg, mi spiace, ho cambiato console.log per avvisare e ho dimenticato di concatenare i due parametri su una singola stringa.
Dave

1
Questa risposta è stata di grande aiuto, ma ho riscontrato un problema che non è menzionato qui e mi chiedevo se è qualcosa di nuovo che è cambiato o se è qualcosa di strano da parte mia. Quando ho clonato il mio elemento figlio, è stato impostato figlio sul vecchio elemento, fino a quando non ho aggiunto this.props.children.props.children al terzo argomento di cloneElement.
Aphenine,

7
Cosa succede se il bambino viene caricato tramite una route (v4) caricata da una pagina di route separata?
blamb

394

Per un modo leggermente più pulito per farlo, prova:

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

Modifica: per usarlo con più singoli figli (il bambino stesso deve essere un componente) che puoi fare. Testato in 16.8.6

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

10
Stavo usando la risposta più votata, ma questa è molto più semplice! Questa soluzione è anche quella che usano nella pagina degli esempi di reagente-router.
captDaylight

10
Qualcuno potrebbe spiegare come funziona (o cosa effettivamente fa)? Leggendo i documenti , non riuscivo a vedere come questo sarebbe disceso nei bambini e aggiungere quel sostegno a ogni bambino - è questo che è destinato a fare? Se lo fa, come facciamo a sapere che è quello che farà? Non è affatto ovvio che sia anche valido passare una struttura dati opaca ( this.props.children) a cloneElement... che si aspetta un ... elemento.
GreenAsJade,

51
Esattamente, questo non sembra funzionare con più di un bambino.
Danita,

17
Quindi puoi scrivere codice che funziona mentre qualcuno passa solo un figlio in un componente, ma quando ne aggiunge un altro, si blocca ... non suona bene con il valore nominale? Sembrerebbe essere una trappola per l'OP, che ha chiesto specificamente di passare oggetti di scena a tutti i bambini.
GreenAsJade,

10
@GreenAsJade va bene fintanto che il tuo componente aspetta un bambino singolo. È possibile definire tramite i componenti propTypes che si aspetta un singolo figlio. React.Children.onlyLa funzione restituisce l'unico figlio o genera un'eccezione se ce ne sono più (questo non esisterebbe se non ci fosse un caso d'uso).
cchamberlain,

80

Prova questo

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

Ha funzionato per me usando reattivo-15.1.


3
È possibile tornare React.cloneElement()direttamente senza racchiuderlo nei <div>tag? Perché cosa succede se il bambino è un <span>(o qualcos'altro) e vogliamo preservare il suo tipo di elemento tag?
Adrianmc,

1
Se è un bambino, puoi lasciare fuori il wrapper e questa soluzione funziona solo per un bambino, quindi sì.
ThaJay

1
Per me va bene. Senza racchiudere <div> è ok.
Crash Override

4
Se devi imporre esplicitamente che ricevi solo un figlio, puoi fare ciò React.cloneElement(React.Children.only(this.props.children), {...this.props})che genererà un errore se viene passato più di un figlio. Quindi non è necessario avvolgere un div.
itsananderson,

1
Questa risposta può produrre un TypeError: valore oggetto ciclico. A meno che tu non voglia che uno degli oggetti di scena del bambino sia se stesso, usa let {children, ...acyclicalProps} = this.propse poi React.cloneElement(React.Children.only(children), acyclicalProps).
Parabolord,

69

Passare oggetti di scena ai bambini diretti.

Vedi tutte le altre risposte

Passa i dati globali condivisi attraverso l'albero dei componenti tramite il contesto

Il contesto è progettato per condividere dati che possono essere considerati "globali" per un albero di componenti di React, come l'utente autenticato, il tema o la lingua preferita. 1

Disclaimer: questa è una risposta aggiornata, la precedente utilizzava la vecchia API di contesto

Si basa sul principio Consumatore / Fornire. Innanzitutto, crea il tuo contesto

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

Quindi utilizzare via

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

e

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

Tutti i consumatori che sono discendenti di un Provider eseguiranno nuovamente il rendering ogni volta che il valore prop del Provider cambia. La propagazione dal provider ai suoi consumatori discendenti non è soggetta al metodo shouldComponentUpdate, quindi il consumatore viene aggiornato anche quando un componente antenato si disconnette dall'aggiornamento. 1

Esempio completo, codice semi-pseudo.

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
A differenza della risposta accettata, questo funzionerà correttamente anche quando ci sono altri elementi inclusi in Parent. Questa è sicuramente la risposta migliore.
Zaptree,

6
Props! = Context
Petr Peller l'

non puoi dipendere dalle modifiche che si propagano attraverso il contesto. Usa gli oggetti di scena quando è possibile che cambino.
ThaJay

1
Forse non capisco ma non è sbagliato dire "il contesto rende disponibili gli oggetti di scena"? L'ultima volta che ho usato il contesto, era una cosa separata (cioè this.context) - non univa magicamente il contesto con oggetti di scena. Dovevi impostare e utilizzare intenzionalmente il contesto, che è un'altra cosa.
Josh,

Hai capito perfettamente, non era corretto. Ho modificato la mia risposta.
Lyubomir,

48

Passare oggetti di scena ai bambini nidificati

Con l'aggiornamento a React 16.6 ora puoi usare 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 brilla dove il caso React.cloneElement non è in grado di gestire componenti nidificati

class SomeComponent extends React.Component {

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

3
Puoi spiegare perché le funzioni => sono una cattiva pratica? La funzione => aiuta a associare i gestori di eventi per ottenere il thiscontesto
Kenneth Truong,

@KennethTruong perché ogni volta che viene visualizzato crea una funzione.
Funziona l'

9
@itdoesntwork non è vero. Crea una nuova funzione solo quando viene creata la classe. Non viene creato durante la funzione di rendering.
Kenneth Truong,

@KennethTruong reactionjs.org/docs/faq-functions.html#arrow-function-in-render pensavo che parlassi della funzione della freccia nel rendering.
Funziona il

24

Puoi usarlo React.cloneElement, è meglio sapere come funziona prima di iniziare a usarlo nella tua applicazione. Viene introdotto React v0.13, continua a leggere per ulteriori informazioni, quindi qualcosa insieme a questo lavoro per te:

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

Quindi porta le righe dalla documentazione di React per farti capire come funziona tutto e come puoi farne uso:

In React v0.13 RC2 introdurremo una nuova API, simile a React.addons.cloneWithProps, con questa firma:

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

A differenza di cloneWithProps, questa nuova funzione non ha alcun comportamento magico incorporato per fondere stile e className per lo stesso motivo per cui non disponiamo di quella funzionalità da transferPropsTo. Nessuno è sicuro di cosa sia esattamente l'elenco completo delle cose magiche, il che rende difficile ragionare sul codice e difficile da riutilizzare quando lo stile ha una firma diversa (ad esempio nel prossimo React Native).

React.cloneElement è quasi equivalente a:

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

Tuttavia, a differenza di JSX e cloneWithProps, conserva anche i riferimenti. Ciò significa che se ottieni un bambino con un riferimento, non lo ruberai accidentalmente al tuo antenato. Otterrai lo stesso riferimento associato al tuo nuovo elemento.

Un modello comune è mappare i tuoi figli e aggiungere un nuovo sostegno. Sono stati segnalati molti problemi relativi alla perdita di ref di cloneWithProps, che rende più difficile ragionare sul codice. Ora seguendo lo stesso modello con cloneElement funzionerà come previsto. Per esempio:

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

Nota: React.cloneElement (child, {ref: 'newRef'}) NON sostituisce il ref, quindi non è ancora possibile che due genitori abbiano un ref sullo stesso figlio, a meno che non si utilizzi callback-refs.

Questa è stata una caratteristica fondamentale per entrare in React 0.13 poiché i puntelli ora sono immutabili. Il percorso di aggiornamento è spesso quello di clonare l'elemento, ma così facendo potresti perdere il riferimento. Pertanto, qui avevamo bisogno di un percorso di aggiornamento migliore. Mentre stavamo aggiornando i callites su Facebook ci siamo resi conto che avevamo bisogno di questo metodo. Abbiamo ricevuto lo stesso feedback dalla community. Pertanto, abbiamo deciso di creare un altro RC prima della versione finale per assicurarci di ottenere questo.

Abbiamo in programma di deprezzare React.addons.cloneWithProps. Non lo stiamo ancora facendo, ma questa è una buona opportunità per iniziare a pensare ai tuoi usi e considerare invece l'utilizzo di React.cloneElement. Spediremo sicuramente una versione con avvisi di deprecazione prima di rimuoverla, quindi non è necessaria alcuna azione immediata.

più qui ...


18

Il modo migliore, che consente di effettuare il trasferimento di proprietà, è childrencome una funzione

Esempio:

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

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

1
Questo mi sembra molto più semplice (e migliore per le prestazioni?) Rispetto alla risposta accettata.
Shikyo

2
Ciò richiede che i bambini siano una funzione e non funziona per i componenti nidificati in modo depurativo
illusione digitale

@digitalillusion, non capisco cosa significhi nested components. React non ha schemi nidificati, solo composizioni. Sì, i bambini devono essere una funzione, non ci sono conflitti, perché questo è un figlio JSX valido. Puoi fare un esempio con nesting components?
Nick Ovchinnikov,

1
Hai ragione, anche il caso dei bambini profondamente nidificati può essere gestito al <Parent>{props => <Nest><ChildComponent /></Nest>}</Parent>posto di (non funziona), <Parent><Nest>{props => <ChildComponent />}</Nest></Parent>quindi sono d'accordo che questa sia la risposta migliore
illusione digitale

Quando provo, ricevo quanto segue:TypeError: children is not a function
Ryan Prentiss il

6

Ho dovuto correggere la risposta accettata sopra per farlo funzionare usando questo invece di questo puntatore. Questo nell'ambito di applicazione della funzione di mappa non ha avuto doSomething funzione definita.

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

Aggiornamento: questa correzione è per ECMAScript 5, in ES6 non è necessario in var that = this


13
o semplicemente usabind()
più-

1
o utilizzare una funzione freccia che si lega all'ambito lessicale, ho aggiornato la mia risposta
Dominic

e se doSomethingprendessi un oggetto, come doSomething: function(obj) { console.log(obj) }e nel Bambino che chiameresti this.props.doSomething(obj)per disconnetterti"obj"
conor909

4
@ plus- so che questo è vecchio, ma usare bind qui è un'idea terribile, bind crea una nuova funzione che lega il contesto a uno nuovo. sostanzialmente una funzione che chiama il applymetodo. l'utilizzo bind()nella funzione di rendering creerà una nuova funzione ogni volta che viene chiamato il metodo di rendering.
Bamieh,

6

Modo più pulito considerando uno o più bambini

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

Questo non funziona per me, dà un errore: bambini non definiti.
Deelux,

@Deelux this.props.children invece dei bambini
Martin Dawson il

questo passa il bambino come i suoi stessi figli this.props. In generale consiglierei solo la clonazione con oggetti di scena specifici, non l'intero shebang.
Andy,

Il passaggio {...this.props}non ha funzionato per me, è la strada {...child.props}corretta?
Felipe Augusto,

Per i componenti funzionali:React.Children.map(children, child => React.cloneElement(child, props))
vsync,

5

Nessuna delle risposte risolve il problema di avere figli NON componenti di React, come stringhe di testo. Una soluzione alternativa potrebbe essere qualcosa del genere:

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

Non hai più bisogno {this.props.children}. Ora si può avvolgere il componente figlio utilizzando renderin Routee passare i vostri oggetti di scena come al solito:

<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
Gli oggetti di scena di rendering sono ora standard in React ( Reamejs.org/docs/render-props.html ) e vale la pena considerarli come una nuova risposta accettata per questa domanda.
Ian Danforth,

19
In che modo questa è una risposta alla domanda?
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('...')
);

vedi esempio qui: https://plnkr.co/edit/jJHQECrKRrtKlKYRpIWl?p=preview



4

Se hai più figli a cui vuoi passare oggetti di scena , puoi farlo in questo modo, usando React.Children.map:

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

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

Se il tuo componente ha un solo figlio, non è necessario mappare, puoi semplicemente clonare Element immediatamente:

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

3

Secondo la documentazione di cloneElement()

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

Clona e restituisci un nuovo elemento React usando l'elemento come punto iniziale. L'elemento risultante avrà i puntelli dell'elemento originale con i nuovi puntelli uniti in modo poco profondo. I nuovi bambini sostituiranno i bambini esistenti. chiave e ref dall'elemento originale verranno conservati.

React.cloneElement() è quasi equivalente a:

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

Tuttavia, conserva anche i riferimenti. Ciò significa che se ottieni un bambino con un riferimento, non lo ruberai accidentalmente al tuo antenato. Otterrai lo stesso riferimento associato al tuo nuovo elemento.

Quindi cloneElement è ciò che useresti per fornire oggetti di scena personalizzati ai bambini. Tuttavia, nel componente possono essere presenti più elementi figlio e sarà necessario eseguirne il ciclo. Ciò che altre risposte suggeriscono è che puoi mapparle su di esse usando React.Children.map. Tuttavia, React.Children.mapdiversamente dalle React.cloneElementmodifiche apportate alle chiavi dell'elemento accodamento e extra .$come prefisso. Controlla questa domanda per maggiori dettagli: React.cloneElement in React.Children.map sta causando la modifica delle chiavi degli elementi

Se desideri evitarlo, dovresti invece optare per la forEachfunzione come

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

}

2

Oltre alla risposta di @and_rest, ecco come clonare i bambini e aggiungere un corso.

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

2

Penso che un oggetto di rendering sia il modo appropriato per gestire questo scenario

Consenti al genitore di fornire gli oggetti di scena necessari utilizzati nel componente figlio, riformattando il codice padre in modo che assomigli a questo:

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

  return children({ doSomething })
}

Quindi nel Componente figlio è possibile accedere alla funzione fornita dal genitore in questo modo:

class Child extends React {

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

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

}

Ora la struttura della fidanzata sarà simile a questa:

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

cosa succede se il genitore è solo un wrapper per un {children} che è un'area di testo in un altro componente di classe?
Adebayo,

2

Metodo 1: clonare i bambini

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

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

Metodo 2: utilizzare il contesto componibile

Il contesto consente di passare un puntello a un componente figlio profondo senza passarlo esplicitamente come puntello attraverso i componenti in mezzo.

Il contesto presenta degli svantaggi:

  1. I dati non fluiscono in modo regolare - tramite oggetti di scena.
  2. L'uso del contesto crea un contratto tra il consumatore e il fornitore. Potrebbe essere più difficile comprendere e replicare i requisiti necessari per riutilizzare un componente.

Utilizzando un contesto componibile

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

Un po 'in ritardo, ma potresti spiegare la notazione in {children}:{children:ReactNode}?
Camille,

@camille, è una cosa dattiloscritta. Guardandolo ora, risponderei solo con Javascript, e anche se scrivessi Typescript, lo farei diversamente. Potrebbe modificarlo in futuro.
Ben Carp

1
@camille, in pratica significa che il valore che ha la chiave "children"è di tipoReactNode
Ben Carp

1

Il modo più semplice per farlo:

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

5
Questo non copia this.props.children in this.props.children del bambino? e in effetti copiando il bambino in se stesso?
Arshabh Agarwal,

1

Per chiunque abbia un singolo elemento figlio questo dovrebbe farlo.

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

0

È questo ciò che hai richiesto?

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
No, non voglio limitare il contenuto del mio wrapper ad alcuni contenuti specifici.
più-

0

Alcuni motivi per cui React.children non lavorava per me. Questo è ciò che ha funzionato per me.

Volevo solo aggiungere una lezione al bambino. simile a cambiare un oggetto

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

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

Il trucco qui è React.cloneElement . Puoi passare qualsiasi oggetto di scena in un modo simile


0

Render props è l'approccio più accurato a questo problema. Invece di passare il componente figlio al componente padre come oggetti di scena figlio, consenti al padre di eseguire il rendering manuale del componente figlio. Render è oggetti di scena incorporati in reag, che accetta il parametro di funzione. In questa funzione è possibile consentire al componente padre di eseguire il rendering di ciò che si desidera con parametri personalizzati. Fondamentalmente fa la stessa cosa degli oggetti di scena per bambini ma è più personalizzabile.

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

Esempio a codepen


0

Quando si utilizzano componenti funzionali, viene spesso visualizzato l' TypeError: Cannot add property myNewProp, object is not extensibleerrore quando si tenta di impostare nuove proprietà props.children. C'è un lavoro intorno a questo clonando gli oggetti di scena e quindi clonando il bambino stesso con i nuovi oggetti di scena.

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>
  )
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.