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

<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中的内置道具,它接受函数参数。在这个函数中,你可以让父组件用自定义参数呈现你想要的任何东西。基本上,它做的事情与子道具相同,但它更可定制。

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

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

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

我需要修复上面接受的答案,以使它使用该指针而不是这个指针。在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

向嵌套子节点传递道具

随着React Hooks的更新,你现在可以使用React了。createContext和useContext。

import * as React from 'react';

// React.createContext accepts a defaultValue as the first param
const MyContext = React.createContext(); 

functional Parent(props) {
  const doSomething = React.useCallback((value) => {
    // Do something here with value
  }, []);

  return (
     <MyContext.Provider value={{ doSomething }}>
       {props.children}
     </MyContext.Provider>
  );
}
 
function Child(props: { value: number }) {
  const myContext = React.useContext(MyContext);

  const onClick = React.useCallback(() => {
    myContext.doSomething(props.value);
  }, [props.value, myContext.doSomething]);

  return (
    <div onClick={onClick}>{props.value}</div>
  );
}

// Example of using Parent and Child

import * as React from 'react';

function SomeComponent() {
  return (
    <Parent>
      <Child value={1} />
      <Child value={2} />
    </Parent>
  );
}

反应。createContext发光的地方React。cloneElement case不能处理嵌套组件

function SomeComponent() {
  return (
    <Parent>
      <Child value={1} />
      <SomeOtherComp>
        <Child value={2} />
      </SomeOtherComp>
    </Parent>
  );
}

在使用函数组件时,当您尝试在props.children上设置新属性时,经常会得到TypeError:不能添加属性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>
  )
}