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


118

我仍然是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,但是文档并未确切说明我何时应该使用它。

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


3
youtube.com/watch?v=hEGg-3pIHlE这个家伙正在展示他如何使用cloneElement。看看一些例子
iurii

Answers:


69

编辑:

相反,请看Vennesa的答案,这是一个更好的解释。

原版的:

首先,该React.cloneElement示例仅在您的孩子是单个React元素时才有效。

几乎所有东西{this.props.children}都是您想要的。克隆在某些更高级的场景中很有用,其中父级发送一个元素,子级组件需要更改该元素上的一些道具或添加诸如ref之类的东西,以访问实际的DOM元素。

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


183

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元素成为消费者。


11
这是一个真实示例的明确答案。它需要更多的支持。
SeaWarrior404 '18

1
同意@ SeaWarrior404-我猜想OP希望遍历一个集合而不是一个孩子,因为他的用户界面具有“ Users” /复数作为标题。使用React.Children.map会同React.cloneElement作为@vennesa指出,功能十分强大
jakeforaker

23

其实React.cloneElement并没有严格的关联this.props.children

每当您需要克隆react elements(PropTypes.element)以添加/覆盖prop而不希望父级不了解有关这些组件内部的知识(例如,附加事件处理程序或分配key/ ref属性)时,此功能将非常有用。

反应元素也是不可变的

React.cloneElement(element,[props],[... children])几乎等同于: <element.type {...element.props} {...props}>{children}</element.type>


但是,childrenReact中的prop特别用于包含(也称为composition),与使用props的React.ChildrenAPI和React.cloneElement组件配对。孩子可以在内部处理更多逻辑(例如状态转换,事件,DOM测量等),同时将渲染部分转换为无论在何处使用,React Router <switch/>或复合组件<select/>都是很好的例子。

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

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.ChildrenReact.cloneElement或甚至React.createContext

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.