我试图找到正确的方法来定义一些组件,这些组件可以以通用的方式使用:

<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}定义一个包装器组件,如何将某些属性传递给它的所有子组件?


当前回答

没有一个答案解决了子组件不是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>

}

其他回答

在我的情况下,React.cloneElement()给了我很多问题,我使用Typescript的函数组件,所以我用孩子(道具)作为一种方式来传递我的道具给我的孩子元素。同样,我的情况非常独特,我必须传递给父组件一个属性,然后基于该属性,它将某些道具传递给子组件。这可以在一个简单的CodeSandbox示例中看到

App.tsx

import "./styles.css";
import Parent from "./Parent";

export default function App() {
  return (
    <>
      <Parent title={"With div wrapper"}>
        {({ title }) => <h1>{title}</h1>}
      </Parent>

      <Parent>
        {({ title }) => <h1>{title === undefined && "this is undefined"}</h1>}
      </Parent>
    </>
  );
}

Parent.tsx

export interface ChildrenProps {
  title?: string;
}

interface ParentWrapperProps {
  children: (title: ChildrenProps) => JSX.Element;
  title?: string;
}

const ParentWrapper: React.FC<ParentWrapperProps> = ({ children, title }) => {
  return title ? (
    <div>{children({ title: title })}</div>
  ) : (
    <>{children({ title: undefined })}</>
  );
};

export default ParentWrapper;

你可以使用React。在开始在应用程序中使用它之前,最好了解它的工作方式。它是在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中)。 反应。cloneElement几乎等同于:

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

然而,与JSX和cloneWithProps不同,它还保留了引用。这 意味着如果你得到一个有裁判的子球,你不会不小心 从你祖先那里偷来。你会得到相同的引用 你的新元素。 一种常见的模式是映射子元素并添加一个新道具。 有许多关于cloneWithProps失去ref的问题报道, 让你的代码更难推理。同样的道理 使用cloneElement的pattern将按预期工作。例如:

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

注意:反应。cloneElement(child, {ref: 'newRef'})会覆盖 所以这仍然是不可能的两个父母有一个裁判 相同的子元素,除非你使用callback-refs。 这是React 0.13的一个关键功能,因为现在有道具了 不可变的。升级路径通常是克隆元素,但通过 这样做你可能会失去裁判。因此,我们需要一个更好的升级 路径。当我们升级Facebook的呼叫网站时,我们意识到这一点 我们需要这个方法。我们从社区得到了同样的反馈。 因此我们决定在最终版本之前再做一个RC 一定要把这个弄进去。 我们计划最终弃用React.addons.cloneWithProps。我们不是 还在做,但这是一个开始思考的好机会 你可以考虑使用React。cloneElement代替。我们会 确保在我们真正发布之前发布一个带有弃用通知的版本 删除它,这样就不需要立即采取行动。

这里……

渲染道具是解决这个问题最准确的方法。不要将子组件作为子道具传递给父组件,而是让父组件手动呈现子组件。渲染是react中的内置道具,它接受函数参数。在这个函数中,你可以让父组件用自定义参数呈现你想要的任何东西。基本上,它做的事情与子道具相同,但它更可定制。

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的例子

也许您还可以发现这个特性很有用,尽管许多人认为这是一种反模式,但如果您知道自己在做什么并设计好解决方案,那么仍然可以使用它。

作为子组件的功能

有一种稍微干净一点的方法,试试:

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