React 设计模式

(一)前言这里提到的设计模式并不是编程通用的设计模式,如常说的单例模式、抽象工厂模式、建造者模式、工厂模式、原型模式等。而是在设计 React 组件时的一些解决方案与技巧,包括以下几种:(1) 容器与展示组件(2) 高阶组件(3) render props(4) context 模式(5) 组合组件(6) 继承当然概念部分,大家能根据名字猜出,但是我还是要为每种,单独给出demo详...
摘要由CSDN通过智能技术生成

(一)前言

这里提到的设计模式并不是编程通用的设计模式,如常说的单例模式、抽象工厂模式、建造者模式、工厂模式、原型模式等。而是在设计 React 组件时的一些解决方案与技巧,包括以下几种:
(1) 容器与展示组件
(2) 高阶组件
(3) render props
(4) context 模式
(5) 组合组件
(6) 继承

当然概念部分,大家能根据名字猜出,但是我还是要为每种,单独给出demo详细说下。
设计模式本身是因为产品需求,解决特定的物业场景,并非完全需要按照这样,所以个人开发中建议形成自己的开发模式。

(二)容器与展示组件

这可能是目前应用最广泛,也是最简单的,大家最推崇的设计方案。其实大概意思就是,将组件分为两种。
一个为容器组件,负责与外部数据进行交互,比如处理业务逻辑(连接redux),
一个为展示组件,只通过props传递业务逻辑,state控制内部交互,不包含任何业务逻辑,也不与外部数据源(连接redux)进行沟通,现在我来举个例子。

需求: 当我们点击按钮后,会去接口拉去数据,并将返回的数据渲染到视图,当然这种需求,简单可以将全部视图写在一起,但是我们需要使用容器和展示组件的方式来组织代码,那么代码如下

// 容器组件 textContainer.js
import React from 'react';
import Text from './text';

class TextContainer extends React.Component {
  state = {
    text: '',
  };

  getData = () => {
    // 模拟异步请求
    setTimeout(() => {
      this.setState({ text: '测试数据' });
    }, 1000);
  };

  render() {
    const {
      state: {
        text,
      },
    } = this;
    return (
      <div>
        <Text text={text} onClick={this.getData} />
      </div>
    );
  }
}

export default TextContainer;

// 展示组件 text.js
import React from 'react';
import PropTypes from 'prop-types';

class Text extends React.PureComponent {
  render() {
    const {
      props: {
        text,
        onClick,
      },
    } = this;
    return (
      <div>
        <div>
        接口返回的数据:
          {text}
        </div>
        <button onClick={onClick}>点我啊</button>
      </div>
    );
  }
}

// 这里我建议,不是必须传入的参数,尽量不使用isRequired验证
// 比如input value 肯定是必须的 但是如果不做受控组件,那么回调onChange就不是必须
Text.defaultProps = {
  text: '',
  onClick: () => null,
};

Text.propTypes = {
  text: PropTypes.string,
  onClick: PropTypes.func,
};

export default Text;

从上面代码我们看出,我们采用软件设计原则中的“责任分离”, 即让一个模块只负责责任尽量单一

容器展示组件这个模式所解决的问题在于,当我们切换数据获取方式时,只需在容器组件修改相应逻辑即可,展示组件无需做改动。展示组件可完全不变,展示组件有了更高的可复用性。

但该模式的缺点也在于将一个组件分成了两部分,增加了代码跳转的成本。并不是说组件包含从外部获取数据,就要将其拆成容器组件与展示组件。

(三)高阶组件

1.概念:
高阶组件不是组件,是 增强函数,可以输入一个元组件,返回出一个新的增强组件;
高阶组件的主要作用是 代码复用,操作状态和参数;

2. 分类(主要两个。一个属性代理,一个反向继承)

  1. 属性代理 : 返回出一个组件,它基于被包裹组件进行功能增强

这里有个获取display name的函数,下面新增的高阶组件都会调用这个方法,就不再次书写了

// 获取display name
function getDisplayName(WrappedComponent) {
  return WrappedComponent.displayName || WrappedComponent.name || 'Component';
}

1.1 默认参数: 可以为组件包裹一层默认参数;

export function ProxyHoc(Component) {
  const NewComponent = (props) => {
    const newProps = {
      name: '高阶组件增加的属性',
      age: 1,
    };
    return <Component {...props} {...newProps} />;
  };
  return NewComponent;
}

1.2 提取状态: 可以通过 props 将被包裹组件中的 state 依赖外层,例如用于转换受控组件:
现在我们来实现一个简单表单高阶组件,不包含表单验证。

// withForm.js
import React from 'react';
import hoistNonReactStatic from 'hoist-non-react-statics';
import { getDisplayName } from './utils';

export default function WithForm(Component) {
  class Enhance extends React.Component {
    static displayName = `WithForm(${getDisplayName(Component)})`;

    state = {
      form: {},
    };

    onChange = key => (e) => {
      const { form } = this.state;
      form[key] = e.target.value;
      this.setState({
        form,
      });
    };

    handleSubmit = () => this.state.form;

    getField = fieldName => ({
      onChange: this.onChange(fieldName),
    });

    render() {
      const newProps = {
        ...this.props,
        getForm: this.handleSubmit,
        setFormItem: this
  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值