如何将道具传递给 this.props.children
Posted
技术标签:
【中文标题】如何将道具传递给 this.props.children【英文标题】:How to pass props to this.props.children如何将道具传递给 this.props.children 【发布时间】:2019-01-07 17:58:35 【问题描述】:我正在尝试找到正确的方法来定义一些可以以通用方式使用的组件:
<Parent>
<Child value="1">
<Child value="2">
</Parent>
当然,父子组件之间的渲染是有逻辑的,你可以把<select>
和<option>
想象成这个逻辑的例子。
出于问题的目的,这是一个虚拟实现:
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>);
);
问题是,每当您使用this.props.children
定义包装组件时,您如何将某些属性传递给它的所有子组件?
【问题讨论】:
我从这个问题的答案中学到了很多东西。我认为 Context API 是当今 React 领域的最佳解决方案。但是如果你想使用 React.cloneElement,我面临的一个问题是没有正确地用React.Children.map()
迭代孩子。在How To Pass Props to react.children中查看更多信息
【参考方案1】:
用新道具克隆孩子
您可以使用React.Children
来迭代子元素,然后使用React.cloneElement
使用新道具(浅合并)克隆每个元素。例如:
const Child = ( doSomething, value ) => (
<button onClick=() => doSomething(value)>Click Me</button>
);
function Parent( children )
function doSomething(value)
console.log("doSomething called by child with value:", value);
const childrenWithProps = React.Children.map(children, child =>
// Checking isValidElement is the safe way and avoids a typescript
// error too.
if (React.isValidElement(child))
return React.cloneElement(child, doSomething );
return child;
);
return <div>childrenWithProps</div>
function App()
return (
<Parent>
<Child value=1 />
<Child value=2 />
</Parent>
);
ReactDOM.render(<App />, document.getElementById("container"));
<script src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
<div id="container"></div>
将孩子作为函数调用
或者,您可以使用render props 将道具传递给孩子。在这种方法中,孩子(可以是children
或任何其他道具名称)是一个可以接受您想要传递的任何参数并返回孩子的函数:
const Child = ( doSomething, value ) => (
<button onClick=() => doSomething(value)>Click Me</button>
);
function Parent( children )
function doSomething(value)
console.log("doSomething called by child with value:", value);
// Note that children is called as a function and we can pass args to it.
return <div>children(doSomething)</div>
function App()
// doSomething is the arg we passed in Parent, which
// we now pass through to Child.
return (
<Parent>
doSomething => (
<React.Fragment>
<Child doSomething=doSomething value=1 />
<Child doSomething=doSomething value=2 />
</React.Fragment>
)
</Parent>
);
ReactDOM.render(<App />, document.getElementById("container"));
<script src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
<div id="container"></div>
如果您愿意,也可以返回一个数组,而不是 <React.Fragment>
或简单的 <>
。
【讨论】:
这对我不起作用。这没有在 React.cloneElement() 中定义 这个答案不起作用,传递给doSomething
的value
丢失了。
@DominicTobias Arg,抱歉,我将 console.log 切换为 alert 并忘记将两个参数连接到单个字符串。
这个答案非常有帮助,但我遇到了一个这里没有提到的问题,我想知道这是改变了一些新的东西还是对我来说很奇怪。当我克隆我的子元素时,它的子元素被设置为旧元素,直到我将 this.props.children.props.children 添加到 cloneElement 的第三个参数。
如果孩子是通过从单独的路由页面加载的路由 (v4) 加载的怎么办?【参考方案2】:
要获得更清洁的方法,请尝试:
<div>
React.cloneElement(this.props.children, loggedIn: this.state.loggedIn )
</div>
编辑: 要与多个单独的孩子一起使用(孩子本身必须是一个组件),您可以这样做。在 16.8.6 中测试
<div>
React.cloneElement(this.props.children[0], loggedIn: true, testPropB: true )
React.cloneElement(this.props.children[1], loggedIn: true, testPropA: false )
</div>
【讨论】:
我使用的是评分最高的答案,但这个答案更直接!这个解决方案也是他们在 react-router 示例页面上使用的。 有人能解释一下它是如何工作的(或者它实际上是做什么的)吗?阅读the docs,我看不出这将如何影响孩子们并将该道具添加到每个孩子身上——这就是它的意图吗?如果是这样,我们怎么知道它会做什么?将不透明的数据结构 (this.props.children
) 传递给 cloneElement
... 这一点也不明显,这需要一个 ... 元素。
没错,这似乎不适用于一个以上的孩子。
因此您可以编写代码,当有人只将一个子元素传递给组件时,它可以工作,但是当他们添加另一个子元素时,它会崩溃……这听起来不太好?对于 OP 来说,这似乎是一个陷阱,他们专门询问将道具传递给 所有 孩子。
@GreenAsJade 只要您的组件期待一个孩子就可以了。您可以通过您的组件 propTypes 定义它需要一个孩子。 React.Children.only
函数返回唯一的孩子,如果有多个则抛出异常(如果没有用例,则不存在)。【参考方案3】:
试试这个
<div>React.cloneElement(this.props.children, ...this.props)</div>
使用 react-15.1 对我有用。
https://reactjs.org/docs/jsx-in-depth.html#spread-attributes建议使用...this.props
【讨论】:
是否可以直接返回React.cloneElement()
而不用<div>
标签括起来?因为如果孩子是<span>
(或其他东西)并且我们想要保留它的标签元素类型怎么办?
如果是一个孩子,你可以省略包装,这个解决方案只适用于一个孩子,所以是的。
为我工作。不包含 是可以的。
如果您需要明确强制您只接收一个孩子,您可以执行React.cloneElement(React.Children.only(this.props.children), ...this.props)
,如果传递多个孩子,则会引发错误。那么你就不需要在一个div中换行了。
这个答案可能会产生 TypeError: cyclic object value。除非您希望孩子的道具之一是它自己,否则请使用let children, ...acyclicalProps = this.props
,然后使用React.cloneElement(React.Children.only(children), acyclicalProps)
。【参考方案4】:
将道具传递给指导孩子。
查看所有其他答案
通过组件树通过context 传递共享的全局数据
上下文旨在共享可被视为 React 组件树“全局”的数据,例如当前经过身份验证的用户、主题或首选语言。 1
免责声明:这是一个更新的答案,上一个使用旧的上下文 API
它基于消费者/提供原则。首先,创建你的上下文
const Provider, Consumer = React.createContext(defaultValue);
然后使用via
<Provider value=/* some value */>
children /* potential consumers */
</Provider>
和
<Consumer>
value => /* render something based on the context value */
</Consumer>
只要 Provider 的 value 属性发生变化,所有作为 Provider 后代的 Consumer 都会重新渲染。 从 Provider 到其后代 Consumer 的传播不受 shouldComponentUpdate 方法的约束,因此即使祖先组件退出更新,Consumer 也会更新。 1
完整示例,半伪代码。
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>
);
1https://facebook.github.io/react/docs/context.html
【讨论】:
与接受的答案不同,即使父项下包含其他元素,它也能正常工作。这绝对是最好的答案。 道具 != 上下文 您不能依赖通过上下文传播的更改。尽可能使用道具。 也许我不明白,但是说“上下文使道具可用”不是错的吗?当我上次使用上下文时,它是一个单独的东西(即this.context
)——它并没有神奇地将上下文与道具合并。您必须有意设置和使用上下文,这是另一回事。
你完全理解,这是不正确的。我已经编辑了我的答案。【参考方案5】:
将道具传递给嵌套的孩子
随着 React 16.6 的更新,您现在可以使用 React.createContext 和 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 在 React.cloneElement 无法处理嵌套组件的情况下大放异彩
class SomeComponent extends React.Component
render()
return (
<Parent>
<Child value=1 />
<SomeOtherComp><Child value=2 /></SomeOtherComp>
</Parent>
);
【讨论】:
你能解释一下为什么 => 函数是一种不好的做法吗? => 函数有助于绑定事件处理程序以获取this
上下文
@KennethTruong 因为每次渲染都会创建一个函数。
@itdoesntwork 这不是真的。它仅在创建类时创建一个新函数。它不是在渲染功能期间创建的..
@KennethTruong reactjs.org/docs/faq-functions.html#arrow-function-in-render 我以为你在谈论渲染中的箭头功能。【参考方案6】:
让您进行财产转移的最佳方式是children
,就像函数模式一样
https://medium.com/merrickchristensen/function-as-child-components-5f3920a9ace9
代码 sn-p:https://stackblitz.com/edit/react-fcmubc
例子:
const Parent = ( children ) =>
const somePropsHere =
style:
color: "red"
// any other props here...
return children(somePropsHere)
const ChildComponent = props => <h1 ...props>Hello world!</h1>
const App = () =>
return (
<Parent>
props => (
<ChildComponent ...props>
Bla-bla-bla
</ChildComponent>
)
</Parent>
)
【讨论】:
对我来说,这似乎比接受的答案更简单(并且性能更好?)。 这要求 children 是一个函数,并且不适用于 deply 嵌套组件 @digitalillusion,我不明白nested components
是什么意思。 React 没有嵌套模式,只有组合。是的,children 必须是一个函数,没有任何冲突,因为这是有效的 JSX 孩子。你能举个nesting components
的例子吗?
你是对的,深层嵌套的孩子的情况也可以处理 <Parent>props => <Nest><ChildComponent /></Nest></Parent>
而不是(不工作)<Parent><Nest>props => <ChildComponent /></Nest></Parent>
所以我同意这是最好的答案
尝试时,我收到以下信息:TypeError: children is not a function
【参考方案7】:
您可以使用React.cloneElement
,最好在开始在应用程序中使用它之前了解它的工作原理。它是在React v0.13
中介绍的,请继续阅读以获取更多信息,因此与此一起为您工作的东西:
<div>React.cloneElement(this.props.children, ...this.props)</div>
因此,请使用 React 文档中的内容来了解它是如何工作的以及如何使用它们:
在 React v0.13 RC2 中我们将引入一个新的 API,类似于 React.addons.cloneWithProps,带有这个签名:
React.cloneElement(element, props, ...children);
与 cloneWithProps 不同,这个新功能没有任何魔力 出于同样的原因,用于合并 style 和 className 的内置行为 我们没有 transferPropsTo 的那个功能。没有人确定是什么 正是魔法事物的完整列表,这使得它 难以对代码进行推理并且在样式时难以重用 有不同的签名(例如在即将到来的 React Native 中)。
React.cloneElement 几乎等同于:
<element.type ...element.props ...props>children</element.type>
但是,与 JSX 和 cloneWithProps 不同的是,它还保留了 refs。这 意味着如果你得到一个带有 ref 的孩子,你不会不小心 从你的祖先那里偷走它。您将获得相同的 ref 附加到 你的新元素。
一种常见的模式是映射你的孩子并添加一个新的道具。 报告了很多关于 cloneWithProps 丢失参考的问题, 让你的代码更难推理。现在遵循相同的 带有 cloneElement 的模式将按预期工作。例如:
var newChildren = React.Children.map(this.props.children, function(child)
return React.cloneElement(child, foo: true )
);
注意:React.cloneElement(child, ref: 'newRef' ) 确实会覆盖 ref 所以两个父母仍然不可能对 同一个孩子,除非你使用回调引用。
这是进入 React 0.13 的一个关键特性,因为 props 现在是 不可变的。升级路径通常是克隆元素,但通过 这样做你可能会失去裁判。因此,我们需要更好的升级 这里的路径。当我们在 Facebook 升级呼叫站点时,我们意识到 我们需要这种方法。我们从社区得到了同样的反馈。 因此我们决定在最终版本发布之前制作另一个 RC 确保我们得到这个。
我们计划最终弃用 React.addons.cloneWithProps。不是 还在做,但这是一个开始思考的好机会 您自己的用途并考虑改用 React.cloneElement。我们会 确保在我们实际发布之前发布带有弃用通知的版本 删除它,因此无需立即采取行动。
更多here...
【讨论】:
【参考方案8】:没有一个答案解决了具有不是 React 组件(例如文本字符串)的子级的问题。解决方法可能是这样的:
// 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>
【讨论】:
【参考方案9】:我需要修复上面接受的答案,以使其使用 that 而不是 this 指针工作。 这个在map函数范围内没有定义doSomething函数。
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 that=this
中不需要【讨论】:
或者直接使用bind()
或者使用绑定到词法范围的箭头函数,我更新了我的答案
如果doSomething
拿了一个对象,比如doSomething: function(obj) console.log(obj)
并且在Child 中你会调用this.props.doSomething(obj)
注销"obj"
会怎样
@plus- 我知道这是旧的,但在这里使用 bind 是一个糟糕的主意,bind 创建了一个新函数,将上下文绑定到一个新函数。基本上是一个调用apply
方法的函数。在渲染函数中使用bind()
会在每次调用渲染方法时创建一个新函数。【参考方案10】:
考虑一个或多个孩子的更简洁的方法
<div>
React.Children.map(this.props.children, child => React.cloneElement(child, ...this.props))
</div>
【讨论】:
这个对我不起作用,它给出了一个错误:children not defined。 @Deelux this.props.children 而不是孩子 这会将this.props
中的孩子作为自己的孩子传递。一般来说,我只建议使用特定的道具进行克隆,而不是整个 shebang。
传递...this.props
对我不起作用,...child.props
的方式正确吗?
功能组件:React.Children.map(children, child => React.cloneElement(child, props))
【参考方案11】:
如果你有多个孩子想要pass props,你可以这样做,使用 React.Children.map:
render()
let updatedChildren = React.Children.map(this.props.children,
(child) =>
return React.cloneElement(child, newProp: newProp );
);
return (
<div>
updatedChildren
</div>
);
如果您的组件只有一个子组件,则无需映射,您可以直接 cloneElement:
render()
return (
<div>
React.cloneElement(this.props.children,
newProp: newProp
)
</div>
);
【讨论】:
【参考方案12】:父.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
【讨论】:
【参考方案13】:受到上述所有答案的启发,这就是我所做的。我正在传递一些道具,比如一些数据和一些组件。
import React from "react";
const Parent = ( children ) =>
const setCheckoutData = actions.shop;
const Input, FieldError = libraries.theme.components.forms;
const onSubmit = (data) =>
setCheckoutData(data);
;
const childrenWithProps = React.Children.map(
children,
(child) =>
React.cloneElement(child,
Input: Input,
FieldError: FieldError,
onSubmit: onSubmit,
)
);
return <>childrenWithProps</>;
;
【讨论】:
写<>childrenWithProps</>
是没用的,因为childrenWithProps
已经是一个数组了。返回childrenWithProps
就足够了。顺便说一句,这个答案与 6 年前选择的答案相同 - 都使用 React.Children.map
然后 cloneElement
【参考方案14】:
除了@and_rest 答案,这就是我克隆孩子并添加类的方式。
<div className="parent">
React.Children.map(this.props.children, child => React.cloneElement(child, className:'child'))
</div>
【讨论】:
【参考方案15】:也许您也可以发现此功能很有用,尽管许多人认为这是一种反模式,但如果您知道自己在做什么并且很好地设计解决方案,它仍然可以使用。
Function as Child Components
【讨论】:
【参考方案16】:我认为渲染道具是处理这种情况的合适方法
您让 Parent 提供子组件中使用的必要道具,方法是重构 Parent 代码,使其看起来像这样:
const Parent = (children) =>
const doSomething(value) =>
return children( doSomething )
然后在子组件中你可以通过这种方式访问父组件提供的功能:
class Child extends React
onClick() => this.props.doSomething
render()
return (<div onClick=this.onClick></div>);
现在最终的结构将如下所示:
<Parent>
(doSomething) =>
(<Fragment>
<Child value="1" doSomething=doSomething>
<Child value="2" doSomething=doSomething>
<Fragment />
)
</Parent>
【讨论】:
如果父级只是另一个类组件中的文本区域 children 的包装器怎么办?【参考方案17】:根据cloneElement()
的文档
React.cloneElement(
element,
[props],
[...children]
)
使用 element 作为起始克隆并返回一个新的 React 元素 观点。结果元素将具有原始元素的道具 随着新道具的浅浅融合。新的孩子将取代 现有的孩子。来自原始元素的 key 和 ref 将是 保存。
React.cloneElement()
几乎等同于:<element.type ...element.props ...props>children</element.type>
但是,它也保留了 refs。这意味着如果你有一个孩子 上面有 ref,你不会不小心从你的祖先那里偷走它。 您将获得附加到新元素的相同 ref。
所以你可以使用 cloneElement 来为孩子提供自定义道具。但是,组件中可以有多个子组件,您需要对其进行循环。其他答案建议您使用React.Children.map
映射它们。然而,React.Children.map
与 React.cloneElement
不同,它改变了元素附加的键和额外的 .$
作为前缀。检查此问题以获取更多详细信息:React.cloneElement inside React.Children.map is causing element keys to change
如果你想避免它,你应该去forEach
这样的函数
render()
const newElements = [];
React.Children.forEach(this.props.children,
child => newElements.push(
React.cloneElement(
child,
...this.props, ...customProps
)
)
)
return (
<div>newElements</div>
)
【讨论】:
【参考方案18】:您不再需要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>
【讨论】:
渲染道具现在是 React 中的标准 (reactjs.org/docs/render-props.html),值得考虑作为这个问题的新接受答案。 这个问题的答案如何? 是的...这不能回答问题,因为问题与反应路由器无关。但是,它确实回答了我与这个问题相关的问题,该问题特定于 react-router。这个基本信息在我能找到的 react-router 网站上的任何地方都不清楚。他们的升级说明中肯定没有提到(非常不完整)。这个答案应该移到它自己的问题上。【参考方案19】:对于任何只有一个子元素的人都应该这样做。
React.isValidElement(this.props.children)
? React.cloneElement(this.props.children,
...prop_you_want_to_pass
)
: null
【讨论】:
【参考方案20】:方法 1 - 克隆孩子
const Parent = (props) =>
const attributeToAddOrReplace= "Some Value"
const childrenWithAdjustedProps = React.Children.map(props.children, child =>
React.cloneElement(child, attributeToAddOrReplace)
);
return <div>childrenWithAdjustedProps </div>
方法 2 - 使用可组合上下文
Context 允许您将 prop 传递给深层子组件,而无需将其作为 prop 显式传递给它们之间的组件。
上下文有缺点:
-
数据不会以常规方式流动 - 通过道具。
使用上下文在消费者和提供者之间创建契约。理解和复制重用组件所需的需求可能会更加困难。
使用可组合的上下文
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>;
;
【讨论】:
有点晚了,你能解释一下children:children:ReactNode
中的符号吗?
@camille,这是一个打字稿。现在看,我只会用 javascript 来回答,即使我会写 Typescript,我也会用不同的方式来做。将来可能会编辑它。
@camille,基本上它意味着具有"children"
键的值的类型是ReactNode
【参考方案21】:
最巧妙的方法:
React.cloneElement(this.props.children, this.props)
【讨论】:
这不是将this.props.children复制到孩子的this.props.children中吗?并且实际上将孩子复制到自身中?【参考方案22】:在使用函数式组件时,尝试在props.children
上设置新属性时,您经常会收到TypeError: Cannot add property myNewProp, object is not extensible
错误。可以通过克隆道具然后使用新道具克隆孩子本身来解决此问题。
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>
)
【讨论】:
【参考方案23】:我在研究类似需求时来到这篇文章,但我觉得克隆解决方案非常流行,太原始并且让我的注意力从功能上移开。
在react文档Higher Order Components找到一篇文章
这是我的示例:
import React from 'react';
const withForm = (ViewComponent) =>
return (props) =>
const myParam = "Custom param";
return (
<>
<div style=border:"2px solid black", margin:"10px">
<div>this is poc form</div>
<div>
<ViewComponent myParam=myParam ...props></ViewComponent>
</div>
</div>
</>
)
export default withForm;
const pocQuickView = (props) =>
return (
<div style=border:"1px solid grey">
<div>this is poc quick view and it is meant to show when mouse hovers over a link</div>
</div>
)
export default withForm(pocQuickView);
对我来说,我找到了一个灵活的解决方案来实现高阶组件的模式。
当然,这取决于功能,但如果其他人正在寻找类似的需求,那很好,这比依赖原始级别的反应代码(如克隆)要好得多。
我积极使用的其他模式是容器模式。一定要阅读它,那里有很多文章。
【讨论】:
【参考方案24】:这是我的版本,适用于单个、多个和无效的孩子。
const addPropsToChildren = (children, props) =>
const addPropsToChild = (child, props) =>
if (React.isValidElement(child))
return React.cloneElement(child, props);
else
console.log("Invalid element: ", child);
return child;
;
if (Array.isArray(children))
return children.map((child, ix) =>
addPropsToChild(child, key: ix, ...props )
);
else
return addPropsToChild(children, props);
;
使用示例:
https://codesandbox.io/s/loving-mcclintock-59emq?file=/src/ChildVsChildren.jsx:0-1069
【讨论】:
【参考方案25】:这是您需要的吗?
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>
)
【讨论】:
不,我不想将包装器的内容限制为某些特定内容。【参考方案26】:React.children 不适合我的一些原因。这对我有用。
我只想为孩子添加一个类。类似于更改道具
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。你可以以类似的方式传递任何道具
【讨论】:
【参考方案27】:Render props 是解决此问题的最准确方法。与其将子组件作为子道具传递给父组件,不如让父组件手动渲染子组件。 Render 是 react 自带的 props,带函数参数。在此函数中,您可以让父组件使用自定义参数呈现您想要的任何内容。基本上它与子道具做同样的事情,但它更可定制。
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>;
Example at codepen
【讨论】:
【参考方案28】:我确实很难让列出的答案起作用,但失败了。最终,我发现问题在于正确设置父子关系。仅仅将组件嵌套在其他组件中并不意味着存在父子关系。
示例1.父子关系;
function Wrapper()
return (
<div>
<OuterComponent>
<InnerComponent />
</OuterComponent>
</div>
);
function OuterComponent(props)
return props.children;
function InnerComponent()
return <div>Hi! I'm in inner component!</div>;
export default Wrapper;
示例 2. 嵌套组件:
function Wrapper()
return (
<div>
<OuterComponent />
</div>
);
function OuterComponent(props)
return <InnerComponent />
function InnerComponent()
return <div>Hi! I'm in inner component!</div>;
export default Wrapper;
正如我上面所说,道具传递在示例 1 的情况下有效。
下面的文章解释一下https://medium.com/@justynazet/passing-props-to-props-children-using-react-cloneelement-and-render-props-pattern-896da70b24f6
【讨论】:
【参考方案29】:如果有人想知道如何在有一个或多个子节点的 TypeScript 中正确执行此操作。我正在使用uuid 库为子元素生成唯一的关键属性,当然,如果您只克隆一个元素,则不需要这些属性。
export type TParentGroup =
value?: string;
children: React.ReactElement[] | React.ReactElement;
;
export const Parent = (
value = '',
children,
: TParentGroup): React.ReactElement => (
<div className=styles.ParentGroup>
Array.isArray(children)
? children.map((child) =>
React.cloneElement(child, key: uuidv4(), value )
)
: React.cloneElement(children, value )
</div>
);
如您所见,此解决方案负责呈现 ReactElement
的数组或单个 ReactElement
,甚至允许您根据需要将属性向下传递给子组件。
【讨论】:
【参考方案30】:这个答案是 w.r.t.反应 v17.x...
将children
用作函数并将props 作为render props
模式传递给它,如下所示:-
<ParentComponent ...anyAdditionalProps>
(actualPropsToPass) => <ChildComponent>children(actualPropsToPass)</ChildComponent>
</ParentComponent>
只需确保必须像渲染道具模式中的函数一样添加实际要投影的内容,以适应子函数中作为prop
传递的参数。
【讨论】:
以上是关于如何将道具传递给 this.props.children的主要内容,如果未能解决你的问题,请参考以下文章