资讯专栏INFORMATION COLUMN

基于Decorator的React高阶组件的思路分析与实现

LinkedME2016 / 3356人阅读

摘要:在深入技术栈一书中,提到了基于的。书里对基于的没有给出完整的实现,在这里实现并记录一下实现的思路。在这里最小的组件就是。对比范式与父组件的范式,如果完全利用来实现的,将操作与分离,也未尝不可,但却不优雅。

在深入react 技术栈一书中,提到了基于Decorator的HOC。而不是直接通过父组件来逐层传递props,因为当业务逻辑越来越复杂的时候,props的传递和维护也将变得困难且冗余。

书里对基于Decorator的HOC没有给出完整的实现,在这里实现并记录一下实现的思路。

整个实现的代码放到了我的Github上,是用来获取豆瓣的电影列表的,npm start即可开箱。

整体思路

书里描述的整体思路,先将整个组件,按照view逻辑抽象为互不重叠的最小的原子组件,使组件间组合更自由。在这里最小的组件就是SearchInput SelectInput List。原子组件一定是纯粹的、木偶式的组件,如果他们自身带有复杂的交互/业务逻辑,那么在组合起来以后可想需要修改多少个原子组件,也就失去了相对配置式的优势。

组件实现 原子组件

这是对原书代码稍加修改的SearchInput原子组件,因为没加Icon,所以改了一下(逃),整体思路不变。原子组件没什么可说的,木偶组件就是接收props来实现功能,是对view层逻辑的抽象。

需要一提的是displayName,是用来确定组件的『身份』的,会被包裹它的组合组件用到,后面会提到组合组件。

export default class SearchInput extends PureComponent {
  static displayName = "SearchInput"

  render() {
    const { onSearch, placeholder } = this.props
    return (
      

SearchSelect

) } }
Decorator组件

先放代码

const searchDecorator = WrappedComponent => {
  class SearchDecorator extends Component {
    constructor(props) {
      super(props)
      this.handleSearch = this.handleSearch.bind(this)
      this.state = {
        keyword: ""
      }
    }

    handleSearch(e) {
      this.setState({
        keyword: e.target.value
      })
      this.props.onSearch(e)
    }

    render() {
      const { keyword } = this.state

      return (
        
      )
    }
  }

Decorator的作用就是将业务/交互逻辑抽象出来进行了处理,view的逻辑还是交由原子组件来实现,可以看到最后的render渲染的还是wrappedComponent,只不过是在经过Decorator之后多了几个props,这些props的中有钩子函数,有要传递给原子组件的参数。

这样,视图逻辑就由view层抽象,交互/业务逻辑由Decorator来抽象。

组合组件

先上代码。

export default class Selector extends Component {
  render() {
    return (
      
{ this.props.children.map((item) => { // SelectInput if (item.type.displayName === "SelectInput") { ... } // SearchInput if (item.type.displayName === "SearchInput") { return React.cloneElement(item, { key: "searchInput", onSearch: this.props.onSearch, placeholder: this.props.searchPlaceholder } ) } // List if (item.type.displayName === "List") { ... }) }
) } }

组合组件的children为根据不同业务需要包裹起来的原子组件,组合组件的逻辑处理功能来自于Decorator,各种Decorator的钩子函数或者参数作为props传递给了Selector,Selector再用它们去完成原子组件之间的交互。组合组件通过之前提到的displayName为不同的原子组件分配props并根据业务需要进行组件间逻辑交互的调整。

一个 Decorator 只做最简单的逻辑,只是给组件增加一个原子的智能特性。业务组件通过组织和拼接 Decorator 来实现功能,而不是改变 Decorator 本身的逻辑。

当我们业务逻辑变得复杂的时候,不要去增加Decorator的复杂度,而是去拼接多个Decorator再通过组合组件去处理具体的业务逻辑,这样能保证Decorator的可复用性。

业务组件
const FinalSelector = compose(asyncSelectDecorator, selectedItemDecorator, searchDecorator)(Selector)

class SearchSelect extends Component {
  render() {
    return (
      
        
        
        
      
    )
  }
}

class App extends Component {
  render() {
    return (
       { console.log(`自定义onSearch: ${e.target.value}`) }}
        onClick={(text) => { console.log(`自定义onClick: ${text}`) }}
        url="/v2/movie/in_theaters"
      />
    )
  }
}

通过compose赋予组合组件不同的逻辑处理功能,然后根据业务需要让compose后的组合组件包含原子组件,最后给从最外层传递参数就完成了。

tips

在实际的场景中也不能滥用HOC,基于Decorator的HOC一般是用来处理偏数据逻辑的部分,而DOM相关的东西就直接简单粗暴的用父组件就好了。

对比 HOC 范式 compose(render)(state) 与父组件(Parent Component)的范式 render(render(state)),如果完全利用 HOC 来实现 React 的 implement,将操作与 view 分离,也未尝不可,但却不优雅。HOC 本质上是统一功能抽象,强调逻辑与 UI 分离。但在实际开发中,前端无法逃离 DOM ,而逻辑与 DOM 的相关性主要呈现 3 种关联形式:

与 DOM 相关,建议使用父组件,类似于原生 HTML 编写

与 DOM 不相关,如校验、权限、请求发送、数据转换这类,通过数据变化间接控制 DOM,可以使用 HOC 抽象

交叉的部分,DOM 相关,但可以做到完全内聚,即这些 DOM 不会和外部有关联,均可

参考资料

深入react 技术栈

基于Decorator的组件扩展实践

精读 React 高阶组件

深入理解 React 高阶组件

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/89607.html

相关文章

  • 学习es7Decorator(顺带写个react高阶组件)

    摘要:为了代码进一步解耦,可以考虑使用高阶组件这种模式。开源的高阶组件使用提供了一系列使用的高阶组件,可以增强组件的行为,可以利用此库学习高阶组件的写法。通过使用此库提供的高阶组件,可以方便地让列表元素可拖动。 1. Decorator基本知识 在很多框架和库中看到它的身影,尤其是React和Redux,还有mobx中,那什么是装饰器呢。 修饰器(Decorator)是一个函数,用来修改类的...

    xiyang 评论0 收藏0
  • 基于Decorator组件扩展实践

    摘要:在业务统一的情况下,仅仅修改组件用于配置的就可以满足业务需求。避免了复杂的图表配置,而将图表进行有效拆分,通过声明式的标签进行组合,从而使图表更具扩展性。而对于颗粒度最细的组件,我们希望它是纯粹的,木偶式的组件。 在前端业务开发中,组件化已经成为我们的共识。沉淀和复用组件,是提高开发效率的利器。但在组件复用的过程中,我们往往会遇到这样的问题,组件相似,却在结构或交互上有些许差别,需要对...

    魏明 评论0 收藏0
  • 深入浅出React高阶组件

    摘要:博客地址背景知识在开始讲述高阶组件前,我们先来回顾高阶函数的定义接收函数作为输入,或者输出另一个函数的一类函数,被称作高阶函数。 博客地址:http://www.luckyjing.com/post... 背景知识 在开始讲述高阶组件前,我们先来回顾高阶函数的定义:接收函数作为输入,或者输出另一个函数的一类函数,被称作高阶函数。对于高阶组件,它描述的便是接受React组件作为输入,输出...

    yuanzhanghu 评论0 收藏0
  • react进阶漫谈

    摘要:父组件向子组件之间非常常见,通过机制传递即可。我们应该听说过高阶函数,这种函数接受函数作为输入,或者是输出一个函数,比如以及等函数。在传递数据的时候,我们可以用进一步提高性能。 本文主要谈自己在react学习的过程中总结出来的一些经验和资源,内容逻辑参考了深入react技术栈一书以及网上的诸多资源,但也并非完全照抄,代码基本都是自己实践,主要为平时个人学习做一个总结和参考。 本文的关键...

    neuSnail 评论0 收藏0
  • react进阶漫谈

    摘要:父组件向子组件之间非常常见,通过机制传递即可。我们应该听说过高阶函数,这种函数接受函数作为输入,或者是输出一个函数,比如以及等函数。在传递数据的时候,我们可以用进一步提高性能。 本文主要谈自己在react学习的过程中总结出来的一些经验和资源,内容逻辑参考了深入react技术栈一书以及网上的诸多资源,但也并非完全照抄,代码基本都是自己实践,主要为平时个人学习做一个总结和参考。 本文的关键...

    wyk1184 评论0 收藏0

发表评论

0条评论

LinkedME2016

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<