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

<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文档《高阶组件》中找到了一篇文章

以下是我的例子:

import React from 'react';

const withForm = (ViewComponent) => {
    return (props) => {

        const myParam = "Custom param";

        return (
            <>
                <div style={{border:"2px solid black", margin:"10px"}}>
                    <div>this is poc form</div>
                    <div>
                        <ViewComponent myParam={myParam} {...props}></ViewComponent>
                    </div>
                </div>
            </>
        )
    }
}

export default withForm;


const pocQuickView = (props) => {
    return (
        <div style={{border:"1px solid grey"}}>
            <div>this is poc quick view and it is meant to show when mouse hovers over a link</div>
        </div>
    )
}

export default withForm(pocQuickView);

对我来说,我在实现高阶组件的模式中找到了一个灵活的解决方案。

当然,这取决于功能,但如果其他人正在寻找类似的需求,这是很好的,这比依赖于原始级别的反应代码,如克隆要好得多。

我经常使用的另一种模式是容器模式。一定要读一读,那里有很多文章。

其他回答

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

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

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>

你不再需要{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>

这是你所要求的吗?

var Parent = React.createClass({
  doSomething: function(value) {
  }
  render: function() {
    return  <div>
              <Child doSome={this.doSomething} />
            </div>
  }
})

var Child = React.createClass({
  onClick:function() {
    this.props.doSome(value); // doSomething is undefined
  },  
  render: function() {
    return  <div onClick={this.onClick}></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>
  )
}

试试这个

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

我用react-15.1就能做到。

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