如何将道具传递给 {this.props.children}

<Parent>
  <Child value="1">
  <Child value="2">
</Parent>
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>);
  }
});

答案

用新道具克隆儿童

您可以使用React.Children遍历子级,然后使用React.cloneElement使用新的道具(浅合并)克隆每个元素,例如:

const Child = ({ doSomething, value }) => (
  <div onClick={() => doSomething(value)}>Click Me</div>
);

class Parent extends React.PureComponent {
  doSomething = value => {
    console.log('doSomething called by child with value:', value);
  }

  render() {
    const childrenWithProps = React.Children.map(this.props.children, child =>
      React.cloneElement(child, { doSomething: this.doSomething })
    );

    return <div>{childrenWithProps}</div>
  }
};

ReactDOM.render(
  <Parent>
    <Child value="1" />
    <Child value="2" />
  </Parent>,
  document.getElementById('container')
);

小提琴: https : //jsfiddle.net/2q294y43/2/

称呼孩子为功能

您也可以将道具传递给带有渲染道具的孩子。在这种方法中,子代(可以是children或任何其他道具名称)是一个函数,可以接受您要传递的任何参数并返回子代:

const Child = ({ doSomething, value }) => (
  <div onClick={() =>  doSomething(value)}>Click Me</div>
);

class Parent extends React.PureComponent {
  doSomething = value => {
    console.log('doSomething called by child with value:', value);
  }

  render() {
    return <div>{this.props.children(this.doSomething)}</div>
  }
};

ReactDOM.render(
  <Parent>
    {doSomething => (
      <React.Fragment>
        <Child doSomething={doSomething} value="1" />
        <Child doSomething={doSomething} value="2" />
      </React.Fragment>
    )}
  </Parent>,
  document.getElementById('container')
);

除了<React.Fragment>或简单地<>您还可以根据需要返回一个数组。

小提琴: https : //jsfiddle.net/ferahl/y5pcua68/7/

对于更简洁的方法,请尝试:

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

编辑:可以与多个单独的子项(子项本身必须是组件)一起使用。在 16.8.6 中测试

<div>
    {React.cloneElement(props.children[0], { loggedIn: true, testingTwo: true })}
    {React.cloneElement(props.children[1], { loggedIn: true, testProp: false })}
</div>

尝试这个

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

它使用 react-15.1 为我工作。

将道具传递给直接的孩子。

查看所有其他答案

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

上下文旨在共享可被视为 React 组件树的 “全局” 数据,例如当前经过身份验证的用户,主题或首选语言。 1 个

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

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

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

然后通过

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

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

只要提供商的价值支柱发生变化,作为提供商的后代的所有消费者都将重新渲染。 从 Provider 到其后代 Consumer 的传播不受 shouldComponentUpdate 方法的约束,因此即使上级组件退出了更新,也要对 Consumer 进行更新。 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

将道具传递给嵌套儿童

随着React 16.6的更新,您现在可以使用React.createContextcontextType

import * as React from 'react';

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

class Parent extends React.Component {
  doSomething = (value) => {
    // Do something here with value
  };

  render() {
    return (
       <MyContext.Provider value={{ doSomething: this.doSomething }}>
         {this.props.children}
       </MyContext.Provider>
    );
  }
}

class Child extends React.Component {
  static contextType = MyContext;

  onClick = () => {
    this.context.doSomething(this.props.value);
  };      

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


// Example of using Parent and Child

import * as React from 'react';

class SomeComponent extends React.Component {

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

React.createContextReact.cloneElement案例无法处理嵌套组件的地方闪耀

class SomeComponent extends React.Component {

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

您可以使用React.cloneElement ,最好在开始在应用程序中使用它之前先了解它的工作方式。它是在React v0.13引入的,请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 不同,此新函数没有合并样式和 className 的任何神奇的内置行为,其原因与我们在 transferPropsTo 中没有该功能的原因相同。没有人可以确定魔术物品的完整清单是什么,这使得很难推理代码,并且当样式具有不同的签名时(例如即将发布的 React Native),也很难重用。

React.cloneElement 几乎等同于:

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

但是,与 JSX 和 cloneWithProps 不同,它还保留引用。这意味着,如果您得到一个带有裁判的孩子,就不会意外地从祖先那里偷走它。您将获得与新元素相同的引用。

一种常见的模式是在孩子身上绘制地图并添加新道具。报告了很多有关 cloneWithProps 丢失引用的问题,这使得推理代码变得更加困难。现在,使用与 cloneElement 相同的模式将按预期工作。例如:

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

注意:React.cloneElement(child,{ref:'newRef'})确实会覆盖 ref,因此,除非您使用 callback-refs,否则两个父对象仍然无法对同一个孩子进行 ref。

这是进入 React 0.13 的关键功能,因为道具现在是不可变的。升级路径通常是克隆元素,但是这样做可能会丢失引用。因此,我们需要一个更好的升级途径。在 Facebook 上升级呼叫站点时,我们意识到我们需要这种方法。我们从社区得到了同样的反馈。因此,我们决定在最终发行版之前再制作一个 RC,以确保我们能收到它。

我们计划最终弃用 React.addons.cloneWithProps。我们还没有这样做,但这是一个很好的机会,可以开始考虑您自己的用途并考虑使用 React.cloneElement。在实际删除发布版本之前,我们一定会先发布其中包含弃用通知的发布版本,因此无需立即采取措施。

这里更多...

允许您进行财产转移的最佳方法是让children喜欢函数

例:

export const GrantParent = () => {
  return (
    <Parent>
      {props => (
        <ChildComponent {...props}>
          Bla-bla-bla
        </ChildComponent>
      )}
    </Parent>
  )
}

export const Parent = ({ children }) => {
    const somePropsHere = { //...any }
    <>
        {children(somePropsHere)}
    </>
}

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

您不再需要{this.props.children} 。现在,您可以在Route使用render包装您的子组件,并像往常一样传递道具:

<BrowserRouter>
  <div>
    <ul>
      <li><Link to="/">Home</Link></li>
      <li><Link to="/posts">Posts</Link></li>
      <li><Link to="/about">About</Link></li>
    </ul>

    <hr/>

    <Route path="/" exact component={Home} />
    <Route path="/posts" render={() => (
      <Posts
        value1={1}
        value2={2}
        data={this.state.data}
      />
    )} />
    <Route path="/about" component={About} />
  </div>
</BrowserRouter>

考虑一个或多个孩子的更清洁方式

<div>
   { React.Children.map(this.props.children, child => React.cloneElement(child, {...this.props}))}
</div>