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

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


当前回答

给孩子们传递道具。

查看所有其他答案

通过上下文通过组件树传递共享的全局数据

Context被设计用来共享React组件树的“全局”数据,比如当前认证的用户、主题或首选语言。1

免责声明:这是一个更新的答案,前一个使用旧的上下文API

它基于消费者/提供原则。首先,创建上下文

const { Provider, Consumer } = React.createContext(defaultValue);

然后使用via

<Provider value={/* some value */}>
  {children} /* potential consumers */
</Provider>

and

<Consumer>
  {value => /* render something based on the context value */}
</Consumer>

当提供者的值道具发生变化时,提供者的所有后代消费者都将重新呈现。从提供者到其后代消费者的传播不受shouldComponentUpdate方法的约束,因此即使在祖先组件退出更新时,消费者也会被更新。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>
    );
  }
}

1 https://facebook.github.io/react/docs/context.html

其他回答

这个答案是w.r.t. React v17.x…

使用子函数作为一个函数,并将道具传递给它作为渲染道具模式,如下所示

 <ParentComponent {...anyAdditionalProps}>
   {
     (actualPropsToPass) => <ChildComponent>{children(actualPropsToPass)}</ChildComponent>
   }
 </ParentComponent>

只是要确保,实际的,要投影的内容必须像渲染道具模式中的函数一样添加,以适应在子函数中作为道具传递的参数。

方法一——克隆儿童

const Parent = (props) => {
   const attributeToAddOrReplace= "Some Value"
   const childrenWithAdjustedProps = React.Children.map(props.children, child =>
      React.cloneElement(child, { attributeToAddOrReplace})
   );

   return <div>{childrenWithAdjustedProps }</div>
}

完整的演示

方法2 -使用可组合的上下文

上下文允许您将道具传递给深度子组件,而无需显式地将其作为道具传递给中间的组件。

环境也有缺点:

数据不会以常规的方式流动——通过道具。 使用上下文将在使用者和提供者之间创建契约。理解和复制重用组件所需的需求可能会更加困难。

使用可组合的上下文

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

根据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>
    )

}

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

你可以在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>

试试这个

<div>{React.cloneElement(this.props.children, {...this.props})}</div>

我用react-15.1就能做到。

使用{…这个。Props}建议在https://reactjs.org/docs/jsx-in-depth.html#spread-attributes