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

IT技术 reactjs
2021-03-28 22:47:31

我仍然是 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个回答

props.children不是真正的孩子;它是孩子们描述符所以你实际上没有什么可以改变的;您不能更改任何props,或编辑任何功能;你只能从中读取如果您需要进行任何修改,必须创建新的元素使用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函数只会看到顶层元素,它不会看到这些元素呈现的任何东西;这意味着您正在向孩子们提供直接props(这里是<Sentence />元素)。如果您需要进一步传递props,假设您将有一个想要使用props<div></div>内部<Sentence />元素,onClick那么在这种情况下,您可以使用 Context API 来做到这一点。使Paragraph提供者和Sentence元素成为消费者。

这是一个真实世界示例的明确答案。它需要更多的赞成票。
2021-05-22 22:47:31
同意@SeaWarrior404 - 我猜想 OP 正在寻找迭代集合而不是单个孩子,因为他的用户界面有“用户”/复数作为标题。使用React.Children.map结合React.cloneElement作为@vennesa指出,功能十分强大
2021-06-19 22:47:31

编辑:

看看Vennesa 的回答,这是一个更好的解释。

原来的:

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

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

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

事实上,React.cloneElement与 没有严格关联this.props.children

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

react元素也是不可变的

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/>都是一些很好的例子。

值得一提的最后一件事是,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 />
      } />
  );
}

它们可以是任何props是有道理的,关键是要定义部件一份不错的合同,这样它的消费者可以从底层实现细节解耦,无论它的使用React.ChildrenReact.cloneElement或甚至React.createContext