深入理解React 高阶组件

本文详细介绍了React中的五种组件形式,重点解析了高阶组件(Higher-Order Components, HOC)的概念和应用。高阶组件是React中用于复用组件逻辑的一种强大工具,它可以接收组件作为参数并返回一个新的组件,增加了组件的功能和行为,降低了代码冗余。文中通过实例展示了如何使用高阶组件处理数据获取和渲染逻辑,以及如何与其他技术如Redux Saga配合,实现复杂的异步操作。文章还提醒了使用高阶组件时的注意事项,如避免在render方法中使用,以及处理静态方法和Refs的问题。" 102713052,9118789,CentOS7 使用yum快速安装Neo4j,"['neo4j', '数据库', 'centos7', 'yum管理', '软件安装']
摘要由CSDN通过智能技术生成

React 中的五种组件形式

目前的前端开发主流技术都已经往组件化方向发展了,而每学一种新的框架的时候,最基础的部分一定是学习其组件的编写方式。这就好像学习一门新的编程语言的时候,总是要从hello world开始一样。而在React中,我们常用的组件编写方式又有哪些呢?或者说各种不同的组件又可以分为几类呢?

无状态组件

无状态组件(Stateless Component)是最基础的组件形式,由于没有状态的影响所以就是纯静态展示的作用。一般来说,各种UI库里也是最开始会开发的组件类别。如按钮、标签、输入框等。它的基本组成结构就是属性(props)加上一个渲染函数(render)。由于不涉及到状态的更新,所以这种组件的复用性也最强。

const PureComponent = (props) => (
    <div>
        //use props
    </div>
)

无状态组件的写法十分简单,比起使用传统的组件定义方式,我通常就直接使用ES6语法中提供的箭头函数来声明这种组件形式。当然,如果碰到稍微复杂点的,可能还会带有生命周期的hook函数。这时候就需要用到Class Component的写法了。

有状态组件

在无状态组件的基础上,如果组件内部包含状态(state)且状态随着事件或者外部的消息而发生改变的时候,这就构成了有状态组件(Stateful Component)。有状态组件通常会带有生命周期(lifecycle),用以在不同的时刻触发状态的更新。这种组件也是通常在写业务逻辑中最经常使用到的,根据不同的业务场景组件的状态数量以及生命周期机制也不尽相同。

class StatefulComponent extends Component {

    constructor(props) {
        super(props);
        this.state = {
            //定义状态
        }
    }

    componentWillMount() {
        //do something
    }

    componentDidMount() {
        //do something
    }
    ... //其他生命周期

    render() {
        return (
            //render
        );
    }
}

容器组件

在具体的项目实践中,我们通常的前端数据都是通过Ajax请求获取的,而且获取的后端数据也需要进一步的做处理。为了使组件的职责更加单一,引入了容器组件(Container Component)的概念。我们将数据获取以及处理的逻辑放在容器组件中,使得组件的耦合性进一步地降低。

var UserListContainer = React.createClass({
  getInitialState: function() {
    return {
      users: []
    }
  },

  componentDidMount: function() {
    var _this = this;
    axios.get('/path/to/user-api').then(function(response) {
      _this.setState({users: response.data});
    });
  },

  render: function() {
    return (<UserList users={this.state.users} />);
  }
});

如上面这个容器组件,就是负责获取用户数据,然后以props的形式传递给UserList组件来渲染。容器组件也不会在页面中渲染出具体的DOM节点,因此,它通常就充当数据源的角色。目前很多常用的框架,也都采用这种组件形式。如:React Redux的connect(), Relay的createContainer(), Flux Utils的Container.create()等。

高阶组件

其实对于一般的中小项目来说,你只需要用到以上的这三种组件方式就可以很好地构造出所需的应用了。但是当面对复杂的需求的时候,我们往往可以利用高阶组件(Higher-Order Component)编写出可重用性更强的组件。那么什么是高阶组件呢?其实它和高阶函数的概念类似,就是一个会返回组件的组件。或者更确切地说,它其实是一个会返回组件的函数。就像这样:

const HigherOrderComponent = (WrappedComponent) => {
  return class WrapperComponent extends Component {
    render() {
      //do something with WrappedComponent
    }
  }
}

做为一个高阶组件,可以在原有组件的基础上,对其增加新的功能和行为。我们一般希望编写的组件尽量纯净或者说其中的业务逻辑尽量单一。但是如果各种组件间又需要增加新功能,如打印日志,获取数据和校验数据等和展示无关的逻辑的时候,这些公共的代码就会被重复写很多遍。因此,我们可以抽象出一个高阶组件,用以给基础的组件增加这些功能,类似于插件的效果。

一个比较常见的例子是表单的校验。

//检验规则,表格组件
const FormValidator = (WrappedComponent, validator, trigger) => {

   getTrigger(trigger, validator) {
      var originTrigger = this.props[trigger];

      return function(event) {
          //触发验证机制,更新状态
          // do something ...
          originTrigger(event);
      }
  }

  var newProps = {
    ...this.props,
    [trigger]:   this.getTrigger(trigger, validator) //触发时机,重新绑定原有触发机制
  };

  return <WrappedComponent  {...newProps} />
}

值得提一句,同样是给组件增加新功能的方法,相比于使用mixins这种方式高阶组件则更加简洁和职责更加单一。你如果使用过多个mixins的时候,状态污染就十分容易发生,以及你很难从组件的定义上看出隐含在mixins中的逻辑。而高阶组件的处理方式则更加容易维护。

另一方面,ES7中新的语法Decorator也可以用来实现和上面写法一样的效果。

function LogDecorator(msg) {
  return (WrappedComponent) => {
    return class LogHoc extends Component {
      render() {
        // do something with this component
        console.log(msg);
        <WrappedComponent {...this.props} />
      }
    }
  }
}

@LogDecorator('hello world')
class HelloComponent extends Component {

  render() {
    //...
  }
}

Render Callback组件

还有一种组件模式是在组件中使用渲染回调的方式,将组件中的渲染逻辑委托给其子组件。就像这样:

import { Component } from "react";

class RenderCallbackCmp extends Component {
  constructor(props) {
    super(props);
    this.state = {
      msg: "hello"
    };
  }

  render() {
    return this.props.children(this.state.msg);
  }
}

const ParentComponent = () =>
  (<RenderCallbackCmp>
    {msg =>
      //use the msg
      <div>
        {msg}
      </div>}
  </RenderCallbackCmp>);

父组件获取了内部的渲染逻辑,因此在需要控制渲染机制时可以使用这种组件形式。







1. 基本概念

高阶组件是React 中一个很重要且较复杂的概念,高阶组件在很多第三方库(如Redux)中都被经常使用,即使你开发的是普通的业务项目,用好高阶组件也能显著提高你的代码质量。

高阶组件的定义是类比于高阶函数的定义。高阶函数接收函数作为参数,并且返回值也是一个函数。类似的,高阶组件接收React组件作为参数,并且返回一个新的React组件。高阶组件本质上也是一个函数,并不是一个组件,这一点一定要注意。

2. 应用场景

为什么React引入高阶组件的概念?它到底有何威力?让我们先通过一个简单的例子说明一下。

假设我有一个组件,需要从LocalStorage中获取数据,然后渲染出来。于是我们可以这样写组件代码:

import React, { Component } from 'react'

class MyComponent extends Component {

  componentWillMount() {
      let data = localStorage.getItem('data');
      this.setState({data});
  }

  render() {
    return <div>{this.state.data}</div>
  }
}

代码很简单,但当我有其他组件也需要从LocalStorage中获取同样的数据展示出来时,我需要在每个组件都重复componentWillMount中的代码,这显然是很冗余的。下面让我们来看看使用高阶组件可以怎么改写这部分代码。

import React, { Component } from 'react'

function withPersistentData(WrappedComponent) {
  return class extends Component {
    componentWillMount() {
      let data = localStorage.getItem('data');
        this.setState({data});
    }

    render() {
      // 通过{...this.props} 把传递给当前组件的属性继续传递给被包装的组件WrappedComponent
      return <WrappedComponent data={this.st
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值