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

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


当前回答

从上面所有的答案中得到启发,这就是我所做的。我传递一些道具,比如一些数据和一些组件。

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

其他回答

你可以使用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代替。我们会 确保在我们真正发布之前发布一个带有弃用通知的版本 删除它,这样就不需要立即采取行动。

这里……

我确实努力让列出的答案工作,但失败了。最终,我发现问题在于正确地建立亲子关系。仅仅在其他组件中嵌套组件并不意味着存在父子关系。

例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- andrend-props -pattern-896da70b24f6

从上面所有的答案中得到启发,这就是我所做的。我传递一些道具,比如一些数据和一些组件。

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

根据cloneElement()的文档

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

克隆并返回一个新的React元素,使用element作为起始元素 点。生成的元素将具有原始元素的道具 新道具浅浅地融合在一起。新的孩子将取代 现有的儿童。原元素的Key和ref将为 保存了下来。 React.cloneElement()几乎等同于: <元素。{…元素类型。道具道具}{…}>{孩子}< / element.type > 然而,它也保留了裁判。这意味着如果你有了孩子 有裁判在上面,你就不会不小心从你的祖先那里偷了它。 你会得到相同的引用附加到你的新元素。

因此,您将使用cloneElement为儿童提供自定义道具。然而,组件中可能有多个子组件,您需要循环遍历它。其他答案建议你使用react。children。map来映射它们。然而React. children .map不同于React。cloneElement更改Element附加项和额外的。$作为前缀的键值。查看这个问题了解更多细节:React。React.Children.map中的cloneElement会导致元素键的改变

如果您希望避免它,您应该改用forEach函数,如

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

}

允许你进行属性转移的最好方法是像函数模式一样的子元素 https://medium.com/merrickchristensen/function-as-child-components-5f3920a9ace9

代码片段: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>
  )
}