Destekleri {this.props.children} adresine nasıl geçirebilirim?


888

Genel bir şekilde kullanılabilecek bazı bileşenleri tanımlamak için uygun bir yol bulmaya çalışıyorum:

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

Tabii ki ebeveyn ve çocuk bileşenleri arasında renderleme için bir mantık var, hayal edebilirsiniz <select>ve <option>bu mantığın bir örneği.

Bu, sorunun amacı için kukla bir uygulamadır:

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

Soru, {this.props.children}bir sarıcı bileşen tanımlamak için her kullandığınızda , bazı özellikleri tüm alt öğelerine nasıl iletirsiniz?


Yanıtlar:


955

Çocukları yeni sahne ile klonlama

Çocukları yinelemek için React.Children'i kullanabilir ve ardından React.cloneElement örn.

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

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

Çocukları işlev olarak adlandırmak

Ayrıca, render sahne olan çocuklara da sahne geçebilirsiniz . Bu yaklaşımda çocuklar ( childrenveya başka bir pervane adı olabilir) geçmek istediğiniz argümanları kabul edebilen ve çocukları döndüren bir işlevdir:

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

İsterseniz <React.Fragment>veya yerine basitçe <>bir dizi döndürebilirsiniz.

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


7
Bu benim için işe yaramıyor. bu React.cloneElement () içinde tanımlanmamıştır
Patrick

12
Bu cevap işe yaramıyor, valuekabulü doSomethingkayboluyor.
Dave

3
@DominicTobias Arg, üzgünüm, console.log'u uyarmak için değiştirdim ve iki parametreyi tek bir dizeye bağlamayı unuttum.
Dave

1
Bu cevap çok yardımcı oldu, ancak burada bahsedilmeyen bir sorunla karşılaştım ve değişen yeni bir şey olup olmadığını veya sonunda garip bir şey olup olmadığını merak ediyordum. Alt öğemi klonladığımda, clo.playElement öğesinin üçüncü argümanına bunu ekleyene kadar alt öğe eski öğeye ayarlandı.
aphenine

7
Çocuk ayrı bir rota sayfasından yüklenen bir rota (v4) aracılığıyla yüklenirse ne olur?
Mart'ta

394

Bunu yapmanın biraz daha temiz bir yolu için şunu deneyin:

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

Düzenleme: Birden fazla çocukla kullanmak için (çocuğun kendisi bir bileşen olmalıdır) yapabilirsiniz. 16.8.6'da test edildi

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

10
En çok oy alan cevabı kullanıyordum, ama bu çok daha basit! Bu çözüm aynı zamanda tepki yönlendirici örnekler sayfasında kullandıklarıdır.
captDaylight

10
Birisi bunun nasıl çalıştığını (veya gerçekte ne yaptığını) açıklayabilir mi? Dokümanları okurken , bunun çocuklara nasıl ineceğini göremedim ve her çocuğa bu pervaneyi ekledim - yapması amaçlanan bu mu? Eğer öyleyse, bunun ne yapacağını nasıl bilebiliriz? Opak bir veri yapısının ( this.props.children) 'ye cloneElement... bir ... elemanı bekleyen geçişinin bile geçerli olduğu açık değildir .
Mayıs 16:55

51
Tam olarak, bu birden fazla çocukla çalışmıyor gibi görünüyor.
Danita

17
Birisi bir bileşene yalnızca bir çocuğu geçirirken çalışan kodu yazabilirsiniz, ancak başka bir bileşen eklediğinde, çöküyor ... bu yüz değerinde harika görünmüyor mu? Özellikle tüm çocuklara yardımcıları geçmesini isteyen OP için bir tuzak gibi görünüyor .
GreenAsJade

10
Bileşeniniz tek bir çocuk beklediği sürece iyi durumda. Bileşenler propTypes aracılığıyla tek bir çocuk beklediğini tanımlayabilirsiniz. React.Children.onlyişlevi yalnızca alt öğeyi döndürür veya birden çok varsa bir istisna atar (kullanım durumu olmasa bu olmazdı).
cchamberlain

80

Bunu dene

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

Reaksiyon-15.1 kullanarak benim için çalıştı.


3
Etiketleri React.cloneElement()çevrelemeden doğrudan geri dönmek mümkün mü <div>? Çünkü çocuk bir <span>(veya başka bir şey) ise ve etiket öğesi türünü korumak istiyorsak ne olur ?
adrianmc

1
Tek bir çocuksa, ambalajı dışarıda bırakabilirsiniz ve bu çözüm sadece bir çocuk için çalışır, bu yüzden evet.
ThaJay

1
Benim için çalışıyor. <div> içine girmeden sorun yok.
Çökme Geçersiz Kılma

4
Yalnızca bir çocuk aldığınızı açıkça zorunlu kılmanız React.cloneElement(React.Children.only(this.props.children), {...this.props})gerekiyorsa, birden fazla çocuk geçirilirse bu hataya neden olur. O zaman bir div'a sarmanıza gerek yok.
itsananderson

1
Bu yanıt bir TypeError: döngüsel nesne değeri üretebilir. Çocuğun aksesuarlarından birinin kendisi olmasını istemiyorsanız, kullanın let {children, ...acyclicalProps} = this.propsve sonra React.cloneElement(React.Children.only(children), acyclicalProps).
Parabolord

68

Çocukları yönlendirmek için sahne geçmek.

Diğer tüm cevapları görün

Paylaşılan, global verileri içerik ağacından içerik yoluyla geçirin

Bağlam, geçerli kimliği doğrulanmış kullanıcı, tema veya tercih edilen dil gibi bir React bileşenleri ağacı için "genel" olarak kabul edilebilecek verileri paylaşmak için tasarlanmıştır. 1

Feragatname: Bu güncellenmiş bir cevaptır, önceki yanıt eski bağlam API'sını kullanmıştır

Tüketici / Tedarik ilkesine dayanmaktadır. İlk olarak, bağlamınızı oluşturun

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

Sonra üzerinden kullanın

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

ve

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

Bir Sağlayıcının torunları olan tüm Tüketiciler, Sağlayıcının değer desteği her değiştiğinde yeniden oluşturulur. Sağlayıcının neslinden gelen Tüketicilere yayılması shouldComponentUpdate yöntemine tabi değildir, bu nedenle bir üst bileşen güncellemeden çıksa bile Tüketici güncellenir. 1

Tam örnek, yarı sahte kod.

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
Kabul edilen cevabın aksine, Ebeveyn kapsamında başka unsurlar olsa bile bu düzgün bir şekilde çalışacaktır. Bu kesinlikle en iyi cevap.
Zaptree

6
Sahne! = İçerik
Petr Peller

bağlam içinde yayılan değişikliklere güvenemezsiniz. Değişmeleri mümkün olduğunda sahne kullanın.
ThaJay

1
Belki anlamıyorum ama "bağlam desteği sağlıyor" demek yanlış değil mi? En son bağlamı kullandığımda, bu ayrı bir şeydi (yani this.context) - bağlamı sahne ile sihirli bir şekilde birleştirmedi. Başka bir şey olan bağlamı kasıtlı olarak ayarlamanız ve kullanmanız gerekiyordu.
Josh

Mükemmel anlıyorsun, yanlıştı. Cevabımı düzenledim.
Lyubomir

48

İç İçe Çocuklara Sahne Geçişi

React 16.6 güncellemesi ile artık React.createContext ve contextType kullanabilirsiniz .

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 , React.cloneElement örneğinin iç içe bileşenleri işleyemediği yerlerde parlıyor

class SomeComponent extends React.Component {

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

3
=> Fonksiyonlarının neden kötü bir uygulama olduğunu açıklayabilir misiniz? => İşlevi, olay işleyicilerinin thisbağlam elde etmesini sağlar
Kenneth Truong

@KennethTruong çünkü bunu her oluşturduğunda bir işlev yaratır.
itdoesntwork

9
@itdoesntwork doğru değil. Yalnızca sınıf oluşturulduğunda yeni bir işlev oluşturur. Render fonksiyonu sırasında yaratılmıyor ..
Kenneth Truong

@KennethTruong reaktjs.org/docs/faq-functions.html#arrow-function-in-render render işlevindeki ok işlevi hakkında konuştuğunuzu düşündüm.
itdoesntwork

24

Bunu kullanabilirsiniz React.cloneElement, uygulamanızda kullanmaya başlamadan önce nasıl çalıştığını bilmek daha iyidir. Sunuldu React v0.13, daha fazla bilgi için okumaya devam edin, bu yüzden sizin için bu çalışma ile birlikte bir şey:

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

Tüm bunların nasıl çalıştığını ve bunlardan nasıl yararlanabileceğinizi anlamak için React belgelerindeki satırları getirin:

React v0.13 RC2'de, bu imza ile React.addons.cloneWithProps'a benzer yeni bir API tanıtacağız:

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

CloneWithProps'ın aksine, bu yeni işlev stil ve className'i birleştirmek için herhangi bir sihirli yerleşik davranışa sahip değildir, aynı nedenle transferPropsTo'dan bu özelliğe sahip değiliz. Kimse sihirli şeylerin tam listesinin tam olarak ne olduğundan emin değil, bu da kod hakkında mantık oluşturmayı ve stilin farklı bir imzası olduğunda (örneğin, yaklaşan React Native'da) yeniden kullanılmasını zorlaştırıyor.

React.cloneElement neredeyse şuna eşittir:

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

Ancak, JSX ve cloneWithProps'ın aksine, ref'leri de korur. Bu, üzerinde ref olan bir çocuk alırsanız, yanlışlıkla atadan çalmayacağınız anlamına gelir. Aynı ref'yi yeni öğenize ekleyeceksiniz.

Yaygın bir model, çocuklarınızın haritasını çıkarmak ve yeni bir pervane eklemektir. CloneWithProps ref kaybetme hakkında bildirilen birçok sorun vardı, bu da kodunuz hakkında akıl yürütmeyi zorlaştırıyor. Şimdi cloneElement ile aynı kalıbı takip etmek beklendiği gibi çalışacaktır. Örneğin:

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

Not: React.cloneElement (child, {ref: 'newRef'}) ref'yi geçersiz kılar, bu nedenle geri arama ref'leri kullanmadığınız sürece iki ebeveynin aynı çocuğa ref sahip olması mümkün değildir.

Sahne şimdi değişmez olduğu için React 0.13'e girmek için kritik bir özellikti. Yükseltme yolu genellikle öğeyi klonlamaktır, ancak bunu yaparak ref kaybedebilirsiniz. Bu nedenle, burada daha güzel bir yükseltme yoluna ihtiyacımız vardı. Facebook'ta çağrı sitelerini yeni sürüme geçirirken bu yönteme ihtiyacımız olduğunu fark ettik. Aynı geri bildirimi topluluktan aldık. Bu nedenle, son sürümden önce bunu aldığımızdan emin olmak için başka bir RC yapmaya karar verdik.

Sonunda React.addons.cloneWithProps'ı kullanımdan kaldırmayı planlıyoruz. Henüz yapmıyoruz, ancak bu kendi kullanımlarınızı düşünmeye başlamak ve bunun yerine React.cloneElement kullanmayı düşünmek için iyi bir fırsat. Gerçekten kaldırmadan önce kullanımdan kaldırma bildirimleri içeren bir sürüm göndereceğimizden emin olacağız, bu yüzden acil bir işlem gerekmez.

daha fazlası burada ...


18

Mülk aktarımı yapmanızı sağlayan en iyi yol childrenbir işlev gibidir

Misal:

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

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

1
Bu benim için kabul edilen cevaptan çok daha basit (ve performans için daha iyi?).
Shikyo

2
Bu, çocukların bir işlev olmasını gerektirir ve büyük ölçüde iç içe geçmiş bileşenler için çalışmaz
dijital yanılsama

@digitalillusion, bunun ne anlama geldiğini anlamıyorum nested components. Tepki iç içe geçmiş kalıplara değil, sadece kompozisyonlara sahiptir. Evet, çocuklar bir işlev olmalı, herhangi bir çakışma yok, çünkü bu geçerli bir JSX çocuğu. İle bir örnek verebilir misiniz nesting components?
Nick Ovchinnikov

1
Haklısın, derin iç içe geçmiş çocuklar <Parent>{props => <Nest><ChildComponent /></Nest>}</Parent>(çalışmayan) yerine de ele alınabilirler, <Parent><Nest>{props => <ChildComponent />}</Nest></Parent>bu yüzden bu en iyi cevaptır
dijital yanılsama

TypeError: children is not a function
Ryan Prentiss

6

Bunun kullanarak çalışır hale getirmek için yukarıda kabul edilen cevabını düzeltmek için gerekli olduğunu yerine bu pointer. Bu harita fonksiyonu kapsamında doSomething fonksiyonu tanımlanmamıştır.

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

Güncelleme: bu düzeltme ECMAScript 5 içindir, ES6'da var =


13
ya da sadece kullanınbind()
artı

1
veya sözcüksel kapsama bağlanan bir ok işlevi kullanın, cevabımı güncelledim
Dominic

ya doSomethingda bir nesneyi doSomething: function(obj) { console.log(obj) }aldıysanız ve Çocukta this.props.doSomething(obj)oturumu kapatmak için "obj"
çağırırdınız

4
@ artı- bunun eski olduğunu biliyorum, ama burada bağlama kullanmak korkunç bir fikir, bağlama bağlamı yeni bir işleve bağlayan yeni bir işlev yaratır. temel olarak applyyöntemi çağıran bir işlev . bind()render işlevinde kullanmak , render yöntemi her çağrıldığında yeni bir işlev oluşturur.
16:38

6

Bir veya daha fazla çocuğu göz önünde bulundurarak daha temiz bir yol

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

Bu benim için çalışmıyor, bir hata veriyor: çocuklar tanımlanmadı.
Deelux

@Deelux this.props.çocuk yerine çocuklar
Martin Dawson

bu çocuğu kendi çocukları gibi geçirir this.props. Genel olarak sadece belirli sahne ile klonlamayı tavsiye ederim, bütün mesele değil.
Andy

Geçmek {...this.props}benim için işe yaramadı, yol {...child.props}doğru mu?
Felipe Augusto

Fonksiyonel bileşenler için:React.Children.map(children, child => React.cloneElement(child, props))
vsync

5

Yanıtların hiçbiri, metin dizeleri gibi React bileşeni OLMAYAN çocuklara sahip olma sorununu ele almaz. Geçici çözüm şöyle bir şey olabilir:

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

Artık ihtiyacınız yok {this.props.children}. Artık kullanarak çocuğunuzun bileşeni sarabilirsiniz renderiçinde Routeve her zamanki gibi sahne geçmesi:

<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
İşleme sahne şimdi React'ta standart olarak ( reaktjs.org/docs/render-props.html ) ve bu soru için kabul edilen yeni bir cevap olarak görülmeye değer.
Ian Danforth

19
Bu sorunun cevabı nasıl?
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)}/>
);

ve 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('...')
);

buradaki örneğe bakın: https://plnkr.co/edit/jJHQECrKRrtKlKYRpIWl?p=preview



4

Sahne geçmek istediğiniz birden fazla çocuğunuz varsa , React.Children.map dosyasını kullanarak bu şekilde yapabilirsiniz:

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

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

Bileşeninizde yalnızca bir çocuk varsa, eşlemeye gerek yoktur, hemen klonlayabilirsiniz.

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

3

Belgelerine göre cloneElement()

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

Öğeyi başlangıç ​​noktası olarak kullanarak yeni bir React öğesini kopyalayın ve döndürün. Ortaya çıkan eleman, yeni elemanın sığ olarak birleştirildiği orijinal elemanın desteklerine sahip olacaktır. Yeni çocuklar mevcut çocukların yerini alacaktır. orijinal öğedeki anahtar ve ref korunacaktır.

React.cloneElement() neredeyse şuna eşittir:

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

Ancak, ref'leri de korur. Bu, üzerinde ref olan bir çocuk alırsanız, yanlışlıkla atadan çalmayacağınız anlamına gelir. Aynı ref'yi yeni öğenize ekleyeceksiniz.

Bu nedenle, cloneElement, çocuklara özel sahne sağlamak için kullanacağınız şeydir. Ancak bileşende birden fazla çocuk olabilir ve bunun üzerinde döngü yapmanız gerekir. Diğer cevapların önerileri, bunları kullanarak eşlemenizdir React.Children.map. Ancak değişikliklerin React.Children.mapaksine React.cloneElementÖğe'nin anahtarları ek .$ve önek olarak eklenir. Daha fazla ayrıntı için bu soruyu kontrol edin: React.Children.map içindeki React.cloneElement öğe anahtarlarının değişmesine neden oluyor

Bunu önlemek istiyorsanız, bunun yerine gitmek gerekir forEachgibi işlevi

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

}

2

@Ve_rest cevabına ek olarak, çocukları bu şekilde klonlayıp bir sınıf ekliyorum.

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

2

Bence bir render pervane bu senaryo için uygun bir yol

Böyle bir şeye bakmak için Ebeveyn kodunu yeniden düzenleyerek Ebeveynin alt bileşende kullanılan gerekli desteği sağlamasına izin verdiniz:

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

  return children({ doSomething })
}

Daha sonra alt Bileşen'de ebeveyn tarafından sağlanan işleve şu şekilde erişebilirsiniz:

class Child extends React {

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

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

}

Şimdi fianl yapısı şöyle görünecek:

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

ebeveyn başka bir sınıf bileşeninde tekdüze olan bir {children} için yalnızca bir sarıcı ise?
Adebayo

2

Yöntem 1 - Klon Çocukları

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

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

Yöntem 2 - Oluşturulabilir Bağlam Kullanın

Bağlam, bir destek parçasını, aradaki bileşenler üzerinden bir destekleyici olarak açıkça geçirmeden derin bir alt bileşene geçirmenize olanak tanır.

Bağlamın dezavantajları vardır:

  1. Veriler, düzenli olarak - sahne araçları yoluyla akmıyor.
  2. Bağlam kullanmak, tüketici ile sağlayıcı arasında bir sözleşme oluşturur. Bir bileşeni yeniden kullanmak için gereken gereksinimleri anlamak ve çoğaltmak daha zor olabilir.

Bileşilebilir bir bağlam kullanma

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

Biraz geç, ama gösterimi açıklayabilir misin {children}:{children:ReactNode}?
camille

@camille, bu bir daktilo yazısı. Şimdi baktığımda, sadece Javascript ile cevap verirdim, ve dakikayı yazsam bile, bunu farklı yapardım. Gelecekte düzenleyebilir.
Ben Carp

1
@camille, temelde anahtara sahip değer demektir "children"tiptedirReactNode
Ben Sazan

1

Bunu yapmanın en şık yolu:

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

5
Bu this.props.children dosyasını çocuğun .props.children dosyasını kopyalamıyor mu? ve aslında çocuğu kendine kopyalamak?
Arshabh Agarwal

1

Tek bir alt öğesi olan herhangi biri için bunu yapmalıdır.

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

0

İstediğin bu mu?

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
Hayır, paketleyicimin içeriğini belirli bir içerikle sınırlamak istemiyorum.
artı-

0

React.children'in benim için çalışmamasının bir nedeni. Bu benim için işe yaradı.

Çocuğa sadece bir sınıf eklemek istedim. pervane değiştirmeye benzer

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

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

Buradaki hile React.cloneElement . Herhangi bir pervaneyi benzer şekilde geçirebilirsiniz


0

Render aksesuvarları bu soruna en doğru yaklaşımdır. Alt bileşen, alt sahne olarak üst bileşene iletmek yerine, üst öğenin alt bileşeni el ile oluşturmasına izin verin. Render , fonksiyon parametresini alan reaksiyonda yerleşik sahne. Bu işlevde, üst bileşenin özel parametrelerle istediğinizi oluşturmasına izin verebilirsiniz. Temelde çocuk sahne ile aynı şeyi yapar, ancak daha özelleştirilebilir.

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

Codepen'de örnek


0

İşlevsel bileşenleri kullanırken, TypeError: Cannot add property myNewProp, object is not extensibleyeni özellikleri ayarlamaya çalışırken sıklıkla hata alırsınız props.children. Sahne etrafında klonlama ve sonra yeni sahne ile çocuğun kendisini klonlama etrafında bir çalışma var.

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>
  )
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.