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

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

其他回答

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

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

有很多方法可以做到这一点。

你可以在parent中传递子元素作为道具。

例1:

function Parent({ChildElement}){
   return <ChildElement propName={propValue} />
}

return <Parent ChildElement={ChildComponent}/>

将子函数作为函数传递

例2:

function Parent({children}){
   return children({className: "my_div"})
}

OR

function Parent({children}){
   let Child = children
   return <Child className='my_div' />
}

function Child(props){
  return <div {...props}></div>
}

export <Parent>{props => <Child {...props} />}</Parent>

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

我认为渲染道具是处理这种情况的合适方法

你可以让父组件提供子组件中使用的必要的道具,通过重构父组件代码使其看起来像这样:

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>