我什么时候应该使用React.cloneElement vs this.props.children?

时间:2016-05-30 09:10:45

标签: reactjs

我仍然是React的菜鸟,在互联网上的许多例子中,我看到渲染子元素的这种变化让我感到困惑。通常我会看到:

class Users extends React.Component {
  render() {
    return (
      <div>
        <h2>Users</h2>
        {this.props.children}
      </div>
    )
  }
}

但后来我看到了这样一个例子:

<ReactCSSTransitionGroup
     component="div"
     transitionName="example"
     transitionEnterTimeout={500}
     transitionLeaveTimeout={500}
     >
     {React.cloneElement(this.props.children, {
       key: this.props.location.pathname
      })}
</ReactCSSTransitionGroup>

现在我理解了api,但docs并没有明确说明何时应该使用它。

那么另一个人做不了什么呢?有人可以用更好的例子向我解释这个吗?

3 个答案:

答案 0 :(得分:60)

props.children不是真正的孩子;这是孩子们的descriptor。所以你实际上没有任何改变;你不能改变任何道具或编辑任何功能;你只能read from it。如果您需要进行任何修改,则必须使用new elements创建React.CloneElement

https://egghead.io/lessons/react-use-react-cloneelement-to-extend-functionality-of-children-components

一个例子:

组件的主要渲染功能,例如App.js

render() {   
    return(
            <Paragraph>
              <Sentence>First</Sentence>
              <Sentence>Second</Sentence>
              <Sentence>Third</Sentence>
            </Paragraph>   
    ) 
}

现在让我们说你需要为onClick的每个孩子添加Paragraph;所以在Paragraph.js你能做到:

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

然后你就可以做到这一点:

render() {   
  return(
        <Paragraph onClick={this.onClick}>
          <Sentence>First</Sentence>
          <Sentence>Second</Sentence>
          <Sentence>Third</Sentence>
        </Paragraph>   
   ) 
}

注意: React.Children.map函数只会看到top level元素,它看不到这些元素呈现的任何内容;这意味着你要为孩子提供直接道具(这里是<Sentence />元素)。如果您需要进一步传递道具,请假设您在其中一个<div></div>元素中有<Sentence />想要使用onClick道具,那么您可以使用Context API来执行此操作。将Paragraph提供者和Sentence元素设为使用者。

答案 1 :(得分:51)

修改

请改为Vennesa's answer,这是一个更好的解释。

<强>原始

首先,if(webView.canGoBack()){ webView.goBack(); } else { finish(); } 示例仅在您的孩子是单个React元素时才有效。

几乎所有React.cloneElement都是你想要的。 克隆在一些更高级的场景中很有用,其中父节点发送一个元素,子组件需要更改该元素上的一些道具或添加像ref这样的东西来访问实际的DOM元素。

在上面的示例中,给孩子的父级不知道组件的关键要求,因此它创建了给定元素的副本,并根据对象中的某个唯一标识符添加了一个键。有关密钥的详细信息:https://facebook.github.io/react/docs/multiple-components.html

答案 2 :(得分:17)

事实上,React.cloneElement并未与this.props.children严格关联。

每当您需要克隆反应元素(PropTypes.element)以添加/覆盖道具时,它都很有用,而不希望父级知道这些组件内部(例如,附加事件处理程序或分配{{ 1}} / key属性)。

反应元素不可变

  

React.cloneElement(element,[props],[... children])几乎相当于:   ref

但是,React中的<element.type {...element.props} {...props}>{children}</element.type>道具特别用于收容(又名composition),与children API和React.Children配对,使用props.children的组件可以在内部处理更多逻辑(例如,状态转换,事件,DOM测量等),同时将渲染部分放到它使用的任何地方,React Router <switch/>或复合组件<select/>是一些很好的例子。

值得一提的最后一件事是反应元素不仅限于props.children。

React.cloneElement

它们可以是任何有意义的道具,关键是为组件定义一个好的合同,以便它的消费者可以与底层的实现细节分离,无论它是否使用{{1 }},function SplitPane(props) { return ( <div className="SplitPane"> <div className="SplitPane-left"> {props.left} </div> <div className="SplitPane-right"> {props.right} </div> </div> ); } function App() { return ( <SplitPane left={ <Contacts /> } right={ <Chat /> } /> ); } ,甚至React.Children