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

Ami*_*ole 99 reactjs

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

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

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

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

现在我理解了api,但是当我应该使用它时,文档并没有完全清楚.

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

Ven*_*esa 121

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>   
    ) 
}
Run Code Online (Sandbox Code Playgroud)

现在让我们说你需要onClick为每个孩子添加一个Paragraph; 所以Paragraph.js你可以这样做:

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

那么你只需要这样做:

render() {   
  return(
        <Paragraph onClick={this.onClick}>
          <Sentence>First</Sentence>
          <Sentence>Second</Sentence>
          <Sentence>Third</Sentence>
        </Paragraph>   
   ) 
}
Run Code Online (Sandbox Code Playgroud)

注意:该React.Children.map函数只能看到top level元素,它看不到那些元素呈现的任何东西; 意思是你要为孩子提供直接道具(这里是<Sentence />元素).如果您需要的道具进一步传递下去,让我们说,你将有一个<div></div>在里面一个<Sentence />想要使用的元素onClick道具,然后在这种情况下,你可以使用Context API做到这一点.将Paragraph提供者和Sentence元素作为消费者.

  • 这是一个真实世界的例子.它需要更多的赞成. (8认同)

Mor*_*sen 59

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

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

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


Xle*_*lee 22

实际上,React.cloneElement并不是严格关联的this.props.children.

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

反应元素也是不可变的.

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


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

值得一提的最后一件事是反应元素不仅限于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 />
      } />
  );
}
Run Code Online (Sandbox Code Playgroud)

它们可以是任何有意义的道具,关键是为组件定义一个好的合同,以便它的消费者可以与底层的实现细节分离,无论它是否正在使用React.Children,React.cloneElement甚至是React.createContext.