Вы могли бы сделать несколько вещей. Один из примеров - это элементы в списке Animal
Используя ваш код:
cat.Play ( новый список & lt; Cat & gt; (). Cast & lt; Animal & gt; (). ToList ());
Другим является создание Animal
generic, поэтому cat.Play (новый List & lt; Cat & gt; ());
будет работать. [ ! d13]
класс Animal & lt; T & gt; {public virtual void Play (List & lt; T & gt; животные) {}} класс Cat: Animal & lt; Cat & gt; {public override void Play (List & lt; Cat & gt; cats) {}} class Program {static void Main (string [] args) {Cat cat = new Cat (); cat.Play (новый список & lt; Cat & gt; ()); }}
Другим способом является не создание Animal
generic, а метод Play
и ограничение этого на T: Animal
класс Animal {public virtual void Play & lt; T & gt; (List & lt; T & gt; животные), где T: Animal {}} класс Cat: Animal {public override void Play & lt; T & gt; (List & lt; T & gt; животные) {}}
Наконец, если вы находитесь на C # 4 и вам нужно только перечислить список и не изменять его, проверьте ответ Эрика Липперта на IEnumerable & л; Животное & GT;!.! [D9] [D15]
Вы можете использовать React.Children для итерации над дочерними элементами, а затем клонировать каждый элемент новыми реквизитами (неглубоким объединением), используя React.cloneElement , например:
const Child = ({ doSomething, value }) => (
<div onClick={() => doSomething(value)}>Click Me</div>
);
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 <div>{childrenWithProps}</div>
}
};
ReactDOM.render(
<Parent>
<Child value="1" />
<Child value="2" />
</Parent>,
document.getElementById('container')
);
Fiddle: https://jsfiddle.net/2q294y43/2/
Попробуйте это
<div>{React.cloneElement(this.props.children, {...this.props})}</div>
Он работал для меня с помощью реакции-15.1.
React.cloneElement()
напрямую, не окружая его в тегах <div>
? Потому что, если ребенок является <span>
(или что-то еще), и мы хотим сохранить его тип элемента тега?
– adrianmc
17 December 2016 в 04:45
React.cloneElement(React.Children.only(this.props.children), {...this.props})
, который выдает ошибку, если ему передается более одного ребенка. Тогда вам не нужно обертывать div.
– itsananderson
21 August 2017 в 22:05
let {children, ...acyclicalProps} = this.props
, а затем React.cloneElement(React.Children.only(children), acyclicalProps)
.
– Parabolord
16 June 2018 в 18:57
Возможно, вы также можете найти полезную эту функцию, хотя многие люди считают ее анти-шаблоном, которую все еще можно использовать, если вы знаете, что делаете, и хорошо разработайте свое решение.
Вы можете использовать React.cloneElement
, лучше знать, как это работает, прежде чем вы начнете использовать его в своем приложении. Это введено в React v0.13
, читайте дальше для получения дополнительной информации, поэтому что-то вместе с этой работой для вас:
<div>{React.cloneElement(this.props.children, {...this.props})}</div>
Поэтому приведите строки из документации React для вас, чтобы понять, как все это работает и как вы может использовать их:
В React v0.13 RC2 мы представим новый API, похожий на React.addons.cloneWithProps, с этой сигнатурой:
blockquote>React.cloneElement(element, props, ...children);
В отличие от cloneWithProps, эта новая функция не имеет никакого волшебного встроенного поведения для слияния стиля и className по той же причине, что у нас нет этой функции от transferPropsTo. Никто не уверен, что именно представляет собой полный список волшебных вещей, что затрудняет разузнание кода и трудно повторное использование, когда стиль имеет другую подпись (например, в предстоящем React Native).
React. cloneElement почти эквивалентен:
blockquote><element.type {...element.props} {...props}>{children}</element.type>
Однако, в отличие от JSX и cloneWithProps, он также сохраняет ссылки. Это означает, что если вы получите ребенка с рефлексией на нем, вы случайно не украдете его у своего предка. Вы получите тот же ref, что и ваш новый элемент.
Один общий шаблон - это сопоставление с вашими детьми и добавление новой опоры. Было много сообщений о том, что cloneWithProps потерял ref, что затрудняет рассуждение о вашем коде. Теперь, следуя той же схеме с cloneElement, будет работать так, как ожидалось. Например:
blockquote>var newChildren = React.Children.map(this.props.children, function(child) { return React.cloneElement(child, { foo: true }) });
Примечание: React.cloneElement (child, {ref: 'newRef'}) Отменяет ref, поэтому для двух родителей иметь ссылку на одного и того же ребенка, если вы не используете callback-refs.
Это была важная функция, чтобы попасть в React 0.13, поскольку реквизиты теперь неизменяемы. Путь обновления часто клонирует элемент, но при этом вы можете потерять ref. Поэтому нам нужен был более удобный путь обновления. Когда мы обновляли callites в Facebook, мы поняли, что нам нужен этот метод. Мы получили те же отзывы от сообщества. Поэтому мы решили сделать еще один RC перед окончательным выпуском, чтобы убедиться, что мы это получим.
Мы планируем в конечном итоге отказаться от React.addons.cloneWithProps. Мы еще не делаем этого, но это хорошая возможность начать думать о ваших собственных потребностях и вместо этого использовать React.cloneElement. Мы обязательно отправим выпуск с уведомлениями об отказе, прежде чем мы удалим его, поэтому немедленное действие не потребуется.
blockquote>больше здесь ...
Это то, что вам нужно?
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>
}
})
Для немного более чистого способа сделать это, попробуйте:
<div>
{React.cloneElement(this.props.children, { loggedIn: this.state.loggedIn })}
</div>
Примечание: это будет работать только в том случае, если есть один ребенок, и это действительный элемент React.
this.props.children
) до cloneElement
..., которая ожидает элемент ..., даже допустимо.
– GreenAsJade
28 March 2016 в 21:55
React.Children.only
возвращает единственного дочернего элемента или выбрасывает исключение, если его несколько (это не было бы, если бы не был случай использования).
– cchamberlain
5 May 2016 в 18:14
Некоторая причина, по которой React.children не работал на меня. Это то, что сработало для меня.
Я хотел просто добавить класс к ребенку. аналогично изменению prop
var newChildren = this.props.children.map((child) => {
const className = "MenuTooltip-item " + child.props.className;
return React.cloneElement(child, { className });
});
return <div>{newChildren}</div>;
Трюк здесь - React.cloneElement . Вы можете передать любую опору аналогичным образом
С обновлением для React 16.3 теперь вы можете использовать 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 (
<ParentProvider value={{ onClick: this.doSomething }}>
{this.props.children}
</ParentProvider>
);
}
}
class Child extends React.Component {
render() {
const { value } = this.props;
return (
<ChildConsumer>
(({ doSomething }) => {
return <div onClick={() => doSomething(value)}>{value}</div>
})
</ChildConsumer>
);
}
}
// Example of using Parent and Child
import * as React from 'react';
class SomeComponent extends React.Component {
render() {
<Parent>
<Child value={1} />
<Child value={2} />
</Parent>
}
}
React.createContext сияет, где case React.cloneElement не может обрабатывать вложенные компоненты
blockquote>class SomeComponent extends React.Component { render() { <Parent> <Child value={1} /> <SomeOtherComp><Child value={2} /></SomeOtherComp> </Parent> } }
Посмотреть все другие ответы
Контекст предназначен для обмена данными, которые можно считать «глобальными» для дерева компонентов React, таких как текущий аутентифицированный пользователь, тема или предпочтительный язык. 1
blockquote>Отказ от ответственности: это обновленный ответ, предыдущий использовал старый контекстный API
Он основан на принципе Consumer / Provide , Во-первых, создайте свой контекст
const { Provider, Consumer } = React.createContext(defaultValue);
Затем используйте через
<Provider value={/* some value */}>
{children} /* potential consumers */
<Provider />
и
<Consumer>
{value => /* render something based on the context value */}
</Consumer>
Все потребители, являющиеся потомками Провайдера будет повторно отображаться всякий раз, когда изменяется значение поддержки поставщика. Распространение от Провайдера к его Потребителям-потомкам не подлежит методу shouldComponentUpdate, поэтому потребитель обновляется даже тогда, когда компонент-предок освобождается от обновления. 1
blockquote>Полный пример, полу-псевдокод.
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> ); } }
this.context
) - она не волшебным образом объединяла контекст с реквизитами. Вы должны были преднамеренно установить и использовать контекст, который является совершенно другим.
– Josh
21 April 2017 в 12:37
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)}/>
);
и 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('...')
);
см. пример здесь: https://plnkr.co/edit/jJHQECrKRrtKlKYRpIWl?p=preview
Если у вас есть несколько детей, которых вы хотите передать реквизиты , вы можете сделать это таким образом, используя React.Children.map:
render() {
let updatedChildren = React.Children.map(this.props.children,
(child) => {
return React.cloneElement(child, { newProp: newProp });
});
return (
<div>
{ updatedChildren }
</div>
);
}
Если ваш компонент имеет только одного ребенка, нет необходимости в сопоставлении, вы можете просто клонировать элемент сразу:
render() {
return (
<div>
{
React.cloneElement(this.props.children, {
newProp: newProp
})
}
</div>
);
}
Самый быстрый способ сделать это:
{React.cloneElement(this.props.children, this.props)}
Мне нужно было исправить принятый ответ выше, чтобы он работал, используя вместо этого указателя.
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>
}})
Обновление: это исправление для ECMAScript 5, в ES6 нет необходимости в var, что = this
doSomething
взял объект, например doSomething: function(obj) { console.log(obj) }
, а в Ребенке вы вызывали this.props.doSomething(obj)
для выхода из "obj"
– conor909
10 April 2016 в 09:39
apply
. использование функции bind()
в функции рендеринга будет создавать новую функцию каждый раз при вызове метода визуализации.
– Bamieh
20 November 2016 в 14:38
Более чистый способ рассмотрения одного или нескольких детей
<div>
{ React.Children.map(this.props.children, child => React.cloneElement(child, {...this.props}))}
</div>
this.props
. В общем, я бы рекомендовал клонирование только с конкретными реквизитами, а не с целым шебангом.
– Andy
2 November 2017 в 07:21
{...this.props}
не сработала для меня, правильно ли {...child.props}
?
– Felipe Augusto
6 July 2018 в 07:11
Ни один из ответов не касается вопроса о том, что у детей есть НЕ РЕАКТИВНЫЕ компоненты, такие как текстовые строки. Обходной путь может быть примерно таким:
// 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>
}
Это можно сделать просто как:
interface PaginationItemProps extends React.HTMLProps<HTMLDivElement> {
}
const PaginationItem = (props: PaginationItemProps) => {
return <div>{props.children}</div>;
}
class Pagination extends React.Component<PaginationProps> {
render() {
return <div>
<PaginationItem>CHILDREN RENDER</PaginationItem>
</div>
}
}
Согласно документации cloneElement()
React.cloneElement(
element,
[props],
[...children]
)
Clone и возвратите новый элемент React, используя элемент в качестве отправной точки. Получившийся элемент будет иметь реквизит оригинального элемента с новым реквизитом, сложенным неглубоко. Новые дети заменят существующих детей. ключ и ref из исходного элемента будут сохранены.
React.cloneElement()
почти эквивалентен:<element.type {...element.props} {...props}>{children}</element.type>
Однако он также сохраняет ссылки. Это означает, что если вы получите ребенка с рефлексией на нем, вы случайно не украдете его у своего предка. Вы получите тот же ref, что и ваш новый элемент.
blockquote>Итак, cloneElement - это то, что вы использовали бы для предоставления пользовательских реквизитов для детей. Однако в компоненте может быть несколько дочерних элементов, и вам нужно будет зациклиться на нем. Другие варианты подсказок позволяют вам сопоставить их с помощью
React.Children.map
. ОднакоReact.Children.map
, в отличие отReact.cloneElement
, изменяет ключи добавления Element и дополнительно.$
в качестве префикса. Проверьте этот вопрос для получения дополнительной информации: React.cloneElement внутри React.Children.map вызывает изменение ключей элементаЕсли вы хотите этого избежать, вместо этого вы должны пойти на
forEach
, напримерrender() { const newElements = []; React.Children.forEach(this.props.children, child => newElements.push( React.cloneElement( child, {...this.props, ...customProps} ) ) ) return ( <div>{newElements}</div> ) }
В ответ на @and_rest ответьте, как я клонировал детей и добавляю класс.
<div className="parent">
{React.Children.map(this.props.children, child => React.cloneElement(child, {className:'child'}))}
</div>
Вам больше не нужно {this.props.children}
. Теперь вы можете обернуть ваш дочерний компонент с помощью render
в Route
и передать свои реквизиты, как обычно:
<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>
value
, переданный вdoSomething
, теряется. – Dave 3 March 2017 в 00:03