如何将道具传递给 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>

当然,父子组件之间的渲染是有逻辑的,你可以把&lt;select&gt;&lt;option&gt;想象成这个逻辑的例子。

出于问题的目的,这是一个虚拟实现:

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>

如果您愿意,也可以返回一个数组,而不是 &lt;React.Fragment&gt; 或简单的 &lt;&gt;

【讨论】:

这对我不起作用。这没有在 React.cloneElement() 中定义 这个答案不起作用,传递给doSomethingvalue丢失了。 @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()而不用&lt;div&gt;标签括起来?因为如果孩子是&lt;span&gt;(或其他东西)并且我们想要保留它的标签元素类型怎么办? 如果是一个孩子,你可以省略包装,这个解决方案只适用于一个孩子,所以是的。 为我工作。不包含 是可以的。 如果您需要明确强制您只接收一个孩子,您可以执行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.createContextcontextType

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.createContextReact.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的例子吗? 你是对的,深层嵌套的孩子的情况也可以处理 &lt;Parent&gt;props =&gt; &lt;Nest&gt;&lt;ChildComponent /&gt;&lt;/Nest&gt;&lt;/Parent&gt; 而不是(不工作)&lt;Parent&gt;&lt;Nest&gt;props =&gt; &lt;ChildComponent /&gt;&lt;/Nest&gt;&lt;/Parent&gt; 所以我同意这是最好的答案 尝试时,我收到以下信息: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 =&gt; 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</>;
;

【讨论】:

&lt;&gt;childrenWithProps&lt;/&gt; 是没用的,因为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.mapReact.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的主要内容,如果未能解决你的问题,请参考以下文章

如何将道具传递给递归子组件并保留所有道具

如何将道具传递给组件的故事?

如何防止将道具传递给内部样式组件

如何将组件中的道具传递给 FlatList renderItem

如何将 Django 变量传递给 Vue 道具

如何将道具传递给来自不同来源的组件?