【问题标题】:When should I be using React.cloneElement vs this.props.children?我应该什么时候使用 React.cloneElement 和 this.props.children?
【发布时间】:2016-09-28 01:19:38
【问题描述】:

我仍然是 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 并没有明确说明我应该何时使用它。

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

【问题讨论】:

标签: reactjs


【解决方案1】:

props.children 不是真正的孩子;它是孩子的​​描述符。所以你实际上没有什么要改变的;您不能更改任何道具,或编辑任何功能;你只能从中读取。如果您需要进行任何修改,您必须使用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>   
    ) 
}

现在假设您需要为Paragraph 的每个孩子添加一个onClick;所以在你的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 函数只会看到 顶级 元素,它看不到这些元素呈现的任何东西;这意味着您正在向孩子提供直接道具(这里是 &lt;Sentence /&gt; 元素)。如果您需要进一步传递道具,假设您将在 &lt;Sentence /&gt; 元素之一内有一个 &lt;div&gt;&lt;/div&gt; 想要使用 onClick 道具,那么在这种情况下,您可以使用 Context API 来做到这一点.将Paragraph 设为提供者,将Sentence 元素设为消费者。

【讨论】:

  • 这是一个真实世界示例的明确答案。它需要更多的支持。
  • 同意@SeaWarrior404 - 我猜 OP 正在寻找迭代一个集合而不是一个孩子,因为他的用户界面有“用户”/复数作为标题。正如@vennesa 指出的那样,将React.Children.mapReact.cloneElement 结合使用非常强大
【解决方案2】:

编辑:

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

原文:

首先,React.cloneElement 示例仅适用于您的孩子是单个 React 元素的情况。

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

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

【讨论】:

    【解决方案3】:

    事实上,React.cloneElementthis.props.children 并不严格关联。

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

    反应元素也是不可变的

    React.cloneElement( element, [props], [...children] ) 几乎等同于: &lt;element.type {...element.props} {...props}&gt;{children}&lt;/element.type&gt;


    然而,React 中的 children prop 专门用于遏制(又名 composition),与 React.Children API 和 React.cloneElement 配对,使用 props.children 的组件可以处理更多逻辑(例如,状态转换、事件、DOM 测量等)在内部,同时将渲染部分生成到任何使用它的地方,React Router &lt;switch/&gt; 或复合组件 &lt;select/&gt; 是一些很好的例子。

    最后值得一提的是,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

    【讨论】:

      猜你喜欢
      • 2017-04-02
      • 1970-01-01
      • 1970-01-01
      • 2021-09-07
      • 2012-09-22
      • 1970-01-01
      • 2015-12-05
      • 2012-12-23
      • 2021-07-13
      相关资源
      最近更新 更多