开发者社区> syfee> 正文

React开发的设计模式及原则

简介: 设计模式是最常见的,通用问题的可复用解决方案的归纳总结,通常被认为是解决该类问题的最佳实践,使用设计模式能帮助我们写出更容易维护,更健壮的代码。设计模式有很多,通常它们都会遵循一些共同的设计原则,接下来我们一起回顾下React社区里出现过的一些设计模式,以及它们所遵循的设计原则。
+关注继续查看
福利推荐:阿里云、腾讯云、华为云等大品牌云产品全线2折优惠活动来袭,4核8G云服务器899元/3年,新老用户共享优惠,点击这里立即抢购>>>

介绍

设计模式是对常见的,通用问题的可复用解决方案的归纳总结,通常被认为是解决该类问题的最佳实践,使用设计模式能帮助我们写出更容易维护,更健壮的代码。设计模式有很多,通常它们都会遵循一些共同的设计原则,接下来我们一起回顾下React社区里出现过的一些设计模式,以及它们所遵循的设计原则。

一些设计原则

  1. 单一职责原则(Single-responsibility?responsibility)?:?每个实体(class,?function,?module)只应该有一个职责。例如当一个组件接收了太多的props,我们应该考虑组件是不是做了太多的事情,有没有必要进行拆分。
  2. 开闭原则(Open-closed?principle):实体(class,?function,?module)?应该对扩展开放,但是对修改关闭。开闭原则意味着应该存在不直接修改的方式扩展实体的功能。
  3. 依赖反转原则(Dependency?inversion?principle):依赖于抽象,而不是具体的实现。依赖注入是一种实现依赖反转的方式。
  4. 不要自我重复?(Don't?repeat?yourself):重复代码会造成代码维护的困难。
  5. Composition?over?inheritance:?通过组合集成的两个组件是松耦合关系,通过props来约束。但是有继承关系的两个组件是强耦合关系,对父组件的修改可能会导致子组件的未预期的结果。

React设计模式

Container?&?presentational?component

把业务组件划分成container组件和presentational组件。?Presentational?component中负责组件的ui渲染,Container?component负责数据的获取和事件的响应。

遵循的设计原则:
  1. 单一职责原则:?Presentational?component负责ui,Container?component负责数据和行为。
  2. Don't?repeat?yourself:?Presentational?component是纯ui组件,不包含业务逻辑,通常可以被复用。
示例
import React from "react";
// Presentational component
export default function ImageList({ images, onClick }) {
  return images.map((img, i) => <img src={img} key={i} onClick={onClick} />);
}
// Container component
export default class ImageListContainer extends React.Component {
  constructor() {
    super();
    this.state = {
      images: []
    };
  }
  componentDidMount() {
    fetch("https://images.com")
      .then(res => res.json())
      .then(({ images }) => this.setState({ images }));
  }
  
  handleClick() {
    // ...
  }
  render() {
    return <ImageList images={this.state.images} onClick={handleClick} />;
  }
}

HOC

Higher-order?component?是一个以组件为参数,返回一个新组件的函数,用于复用组件的逻辑,Redux的?connect?和?Relay的createFragmentContainer都有使用HOC模式。

遵循的设计原则:
  1. Don't?repeat?yourself:把可复用的逻辑放到HOC中,实现代码复用。
  2. Composition?over?inheritance:?hoc中传入的组件和返回的组件是组合的关系,?也可以把多个HOC进行多次的嵌套组合。
示例
import React from "react";
export default function withLoader(Component, url) {
  return class HOC extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        loading: true,
        data: {},
      };
    }
    componentDidMount() {
      fetch(url)
        .then((res) => res.json())
        .then(({ data }) => this.setState({ data }))
        .finally(() => this.setState({loading: false}))
    }
    render() {
      if (this.state.loading) {
        return <div>Loading...</div>;
      }
      return <Component {...this.props} data={this.state.data} />;
    }
  };
}

Render?prop

Render?prop是指组件的使用者通过组件暴露的函数属性来参与定制渲染相关的逻辑。使用Render?prop模式的库包括:?React?Router,?Downshift?and?Formik.

遵循的设计原则:
  1. Don't?repeat?yourself:把可复用的逻辑放到组件中,实现代码复用。
  2. 依赖反转原则:通过render?prop注入渲染相关的实现。
  3. 开闭原则(Open-closed?principle):?通过render?prop暴露扩展点,而不是直接定制组件。
示例
import React from "react";
class Loader extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      loading: true,
      data: {},
    };
  }
  componentDidMount() {
    fetch(url)
      .then((res) => res.json())
      .then(({ data }) => this.setState({ data }))
      .finally(() => this.setState({ loading: false }));
  }
  render() {
    if (this.state.loading) {
      return <div>Loading...</div>;
    }
    return this.props.renderData(this.state.data);
  }
}

Compound?components

Compound?components是指通过多个组件的组合来完成特定任务,这些组件通过共享的状态、逻辑进行关联。典型的例子是Select和Select.Option组件。使用Compound?components模式的库包括:semantic?ui;?

遵循的设计原则:
  1. 单一职责原则(Single-responsibility?responsibility):?拆分成多个组件,每个组件承担自己的职责。
  2. 开闭原则(Open-closed?principle):?需要迭代增强功能时,可以通过创建新的子组件的方式进行扩展。
示例
import React from "react";
const SelectContext = React.createContext({});
export function Select({ value, onChange, children }) {
  const [open, setOpen] = React.useState(false);
  const [val, setValue] = React.useState(value);
  return (
    <div className={`select`}>
      <div
        className="select-value"
        onClick={() => {
          setOpen(true);
        }}
      >
        {val}
      </div>
      <SelectContext.Provider
        value={{
          value: val,
          setOpen,
          setValue: (newValue) => {
            setValue(newValue);
            if (value !== newValue) {
              onChange(newValue);
            }
          },
        }}
      >
        {open && children}
      </SelectContext.Provider>
    </div>
  );
}
function Option({ children, value }) {
  const {
    setOpen,
    setValue,
    value: selectedValue,
  } = React.useContext(SelectContext);
  return (
    <div
      className={`select-option ${value === selectedValue ? "selected" : ""}`}
      onClick={() => {
        setValue(value);
        setOpen(false);
      }}
    >
      {children}
    </div>
  );
}
function OptionGroup({ children, label }) {
  return (
    <div className="select-option-group">
      <div className="select-option-group-label">{label}</div>
      {children}
    </div>
  );
}
Select.Option = Option;
Select.OptionGroup = OptionGroup;
function Demo() {
  const [city, setCity] = React.useState("北京市");
  return (
    <Select value={city} onChange={setCity}>
      <Select.Option value="北京市">北京市</Select.Option>
      <Select.OptionGroup label="河北省">
        <Select.Option value="石家庄市">石家庄市</Select.Option>
        <Select.Option value="保定市">保定市</Select.Option>
      </Select.OptionGroup>
    </Select>
  );
}

Custom?hooks

自定义hooks可以做到把与state和生命周期关联的可复用逻辑封装到独立的函数中,?上面的提及的一些模式都是基于组件的方案,自定义hooks是更细粒度的解决方案。

遵循的设计原则:
  1. Don't?repeat?yourself:把可复用的逻辑放到自定义hooks中,实现代码复用。
  2. 单一职责原则:每个自定义hooks是都是一个独立的逻辑单元。
示例:
import { useState, useEffect } from "react";
function useLoader(url) {
  const [data, setData] = useState({});
  const [loading, setLoading] = useState(false);
  useEffect(() => {
    setLoading(true);
    fetch(url)
      .then((res) => res.json())
      .then(({ data }) => {
        setData({ data });
      })
      .finally(() => setLoading(false));
  }, [url]);
  return { data, loading };
}

结尾

上面提及的曾经在社区流行的设计模式,往往遵守了一些设计原则,从而能帮助开发者写出健壮,易维护的代码。但是我们需要能根据实际的场景做出判断,是否需要引入这些模式,毕竟还有一个设计原则是YAGNI?(You?aren't?gonna?need?it)。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
webpack项目篇(六十六):react 全家桶 和 webpack 开发 h5 商城项目的整体思路
webpack项目篇(六十六):react 全家桶 和 webpack 开发 h5 商城项目的整体思路
20 0
React Native环境配置、初始化项目、打包安装到手机,以及开发小知识
React Native环境配置、初始化项目、打包安装到手机,以及开发小知识
103 0
Django API 开发:Todo 应用的 React 前端(下)
API 的功能在于与其他程序进行通信。 在本文中,我们将通过 React 前端使用上一篇文章中的 Todo API,这样您就可以了解实际中一切如何协同工作。
52 0
Django API 开发:Todo 应用的 React 前端(上)
API 的功能在于与其他程序进行通信。 在本文中,我们将通过 React 前端使用上一篇文章中的 Todo API,这样您就可以了解实际中一切如何协同工作。
42 0
用 React 结合 SAP UI5 Web Components 来开发 SAP Fiori 应用
用 React 结合 SAP UI5 Web Components 来开发 SAP Fiori 应用
68 0
React开发实(3)react 进阶
React开发实(3)react 进阶
68 0
React开发实践(8)实战部分 首页 开发(1)
React开发实践(8)实战部分 首页 开发(1)
67 0
React+Nodejs+MySQL全栈开发入门
React+Nodejs+MySQL全栈开发入门
61 0
+关注
syfee
蚂蚁集团前端开发工程师
文章
问答
文章排行榜
最热
最新
相关电子书
更多
React Native 全量化实践—web 技术打造移动研发新模式
立即下载
搭建React Native生态
立即下载
React在大型后台管理项目中的工程实践
立即下载


http://www.vxiaotou.com