React组件化复用的一些技巧

栏目: 服务器 · 发布时间: 5年前

内容简介:复用是组件化开发体系的立命之本,可以说组件化的初衷就是为了复用性。但是组件化的复用方式也存在一定的问题,其中拆分粒度就是其中一个绕不开的话题,今天咱们就来讲一讲 React 当中的一个不太常用的 API:假如我们有一个比如:

复用是组件化开发体系的立命之本,可以说组件化的初衷就是为了复用性。但是组件化的复用方式也存在一定的问题,其中拆分粒度就是其中一个绕不开的话题,今天咱们就来讲一讲 React 当中的一个不太常用的 API: cloneElement ,他如何帮组我们更好得进行组件拆分。

假如我们有一个 Layout 组件,那么一般来说这个组件主要接收的就是 children ,把它放在主要内容的部分,然后组件本身的节点来控制布局,那么这个时候如果我们这个布局包含两个部分呢,比如还有一个 header 部分,是跟主要内容有明显区分的。

比如:

React组件化复用的一些技巧

那么我们这个时候会如何设计这个组件呢?

版本一

function Layout({ header: Header, children }) {
  return (
    <div className='container'>
      <div className='header'>
        <Header />
      </div>
      <div classNmae='content'>{children}</div>
    </div>
  )
}
复制代码

这应该是我们比较常见的方式,我们通过把具体组件作为 Layoutprops 传入进来,然后按照组件的写法把它写入到组件渲染内容之中。

我们想要使用这个组件,一般会像下面这样:

function Header() {
  return <h1>Title Here</h1>
}

;<Layout header={Header}>
  <div>content here</div>
</Layout>
复制代码

那么这样做有什么问题呢?显然是有的,最明显的就是无法在使用 Header 的时候指定 props

如果 Headerprops ,那么就我们只能硬编码在 Layout 里面,不能在使用 Header 组件的地方进行声明,所以如果我们想要复用一个 Header 组件,我们可能需要再声明一个组件,比如我们给 Header 组件一个叫做 messageprop 用来指定显示的文字内容

function Header({ message = 'Title Here' }) {
  return <h1>{message}</h1>
}
复制代码

那么如果我们想要在不同页面复用这个组件并且显示不同的标题,我们需要这么做:

function BigHeader() {
  return <Header message='The Other Title' />
}
复制代码

这么做显然在组件较为复杂而且 props 较多的情况下,也可以达到一定的复用效果,但是追求极致的我们肯定不希望仅仅局限于此。

第二版

那么有没有办法让我们可以在使用时能指定 props 呢?答案肯定是有的,我们可以将 Layoutheader 这个 prop 接收的不是组件本体,而是具体的 ReactElement

function Layout({ header, children }) {
  return (
    <div className='container'>
      <div className='header'>{header}</div>
      <div classNmae='content'>{children}</div>
    </div>
  )
}
复制代码

那么我们在使用的时候就可以非常方便得指定 props

<Layout header={<Header message='The Other Title' />}>
  <div>Content Here</div>
</Layout>
复制代码

要理解我们可以这么做,首先我们需要弄清楚什么是 ReactElement 。因为我们大部分时候写 React 组件的时候用的都是 JSX ,所以很多同学可能并不知道 ReactElement 的存在。

其实 JSX 经过 babel 翻译之后得到的是如下代码:

// jsx
;<div id='id'>content</div>

// js
React.createElement('div', { id: 'id' }, 'content')
复制代码

这个函数接收三个参数

  • component 具体渲染的组件,包括原生 dom 节点( string )和自定义组件( object )
  • config ,包括所有 props 再加上 keyref 形成的字典对象
  • children ,子节点内容,可以是 ReactElementArraystring 等内容

最后他返回的是一个叫做 ReactElement 类型的对象,他会包含后续 React 渲染过程中需要用到的一个节点包含的所有信息,我们的 props.children 其实就是最典型的 ReactElement

所以在上诉例子中,我们传入的 header 就是一个 ReactElement ,所以可以直接作为其他节点的 children 而使用。

同时使用这种方式我们还获得来一个非常大的优势,那就是我们甚至可以重新定义一个组件,就可以直接使用 Layout

<Layout header={<h1>The Other Title</h1>}>
  <div>Content Here</div>
</Layout>
复制代码

这样同样也是可以行得通的。

那么是否到这里我们就大功告成来呢?NO,NO,NO,我们还是有值得优化的地方。

第三版

试想一下,如果我们的 Layout 中接收来 header 是一个节点,但是呢他希望对传入的组件的一些 props 有强制的要求呢?比如我们的 Header 组件如果还有另外一个 propcolor ,用来指定文字内容的显示颜色:

function Header({ message = 'Title Here', color = 'red' }) {
  return <h1 style={{ color }}>{message}</h1>
}
复制代码

Layout 要求所有传入的 Header 必须颜色是 green ,显示我们也可以在使用 Header 组件的时候自己指定这个 prop ,但是如果我们需要强制指定的 prop 很多,而且使用 Layout 的地方也很多,那么明显我们会写很多重复代码,而且如果后面我们需要修改这个要求的时候也会导致多次修改,甚至有些地方忘了修改而导致 bug。那么这时候我们该怎么做呢?

我们可以使用一个 API,这个 API 并不常用,但是在这种场景下,他却非常有用,这就是 React.cloneElement ,我们来修改一下 Layout

function Layout({ header, children }) {
  return (
    <div className='container'>
      <div className='header'>
        {React.cloneElement(header, { color: 'green' })}
      </div>
      <div classNmae='content'>{children}</div>
    </div>
  )
}
复制代码

通过这样,我们真正渲染出来的 Header 他的 props.color 就永远都是 green 。那么这个 API 是啥意思呢?

顾名思义,他是用来 克隆 一个 ReactElement ,他接收三个参数,第一个是目标 element ,第二个是 props ,第三个是 children 。可见他跟 createElement 非常像,唯一的区别是第一个参数从组件变成来节点。

他做的事情其实就是拷贝目标 element ,并把后面两个参数覆盖原 elementprops ,以此创建一个新的 ReactElement

那么到此,我们的优化过程也差不多来,当然 demo 显然是非常简单的代码,现实中的问题往往要复杂很多,比如接收的如果不是一个 ReactElement 而是数组,字符串该如何处理。那么这些问题在这里就不再继续深入来,留给各位小伙伴自己去思考吧,毕竟万变不离其宗,知道了核心思路之后,其他问题也就可以迎刃而解来。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Definitive Guide to MongoDB

The Definitive Guide to MongoDB

Peter Membrey、Wouter Thielen / Apress / 2010-08-26 / USD 44.99

MongoDB, a cross-platform NoSQL database, is the fastest-growing new database in the world. MongoDB provides a rich document orientated structure with dynamic queries that you’ll recognize from RDMBS ......一起来看看 《The Definitive Guide to MongoDB》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具