React 设计艺术:如何精确拆分组件接口,实现接口隔离原则

接口隔离原则

接口隔离原则(Interface Segregation Principle,简称 ISP)也是面向对象设计中的重要原则之一。它的核心思想是,一个类不应该依赖它不需要的接口。在 React 开发中,遵循接口隔离原则可以提高代码的可维护性和可扩展性。

接口隔离原则的要点如下:

  1. 客户端不应该强迫依赖它不需要的接口。

  2. 接口应该小而精炼,不应该设计过多不相关的方法。

  3. 类应该根据实际需求,仅实现相关的接口。

在 React 中,我们可以通过组件的拆分和组合来实现接口隔离。下面我们通过示例代码来说明:

复制代码
// 接口一:用于显示用户名的组件接口
const UserNameDisplay = ({ username }) => {
  return <div>{username}</div>;
};

// 接口二:用于显示用户头像的组件接口
const UserAvatarDisplay = ({ avatarUrl }) => {
  return <img src={avatarUrl} />;
};

// 使用上述两个接口的用户信息组件
const UserInfo = ({ username, avatarUrl }) => {
  return (
    <div>
      <UserNameDisplay username={username} />
      <UserAvatarDisplay avatarUrl={avatarUrl} />
    </div>
  );
};

在上述示例中,我们定义了两个独立的组件接口:UserNameDisplay 和 UserAvatarDisplay。这两个组件各自负责显示用户名和用户头像。最后,我们使用这两个接口的组合来构建一个用户信息组件 UserInfo。

通过将接口拆分成较小、单一的组件,并通过组合的方式将它们组装起来,我们实现了接口的隔离。这样一来,不同的组件在使用时不会依赖不需要的功能,从而提高了代码的可维护性和可扩展性。

除了组件拆分和组合之外,也可以使用 React 的 Hooks 来实现接口隔离。React Hooks 是 React 16.8 新增的特性,它可以在函数组件中使用 React 的特性。通过使用自定义 Hooks,我们可以将相关的功能封装在一个独立的 Hook 中,从而实现接口隔离。

总结起来,React 中的接口隔离原则可以通过组件的拆分和组合,或者使用 Hooks 来实现。在开发过程中,我们应该遵循以下原则:

  1. 组件的接口应该小而精炼,只包含实际需要的功能。

  2. 将功能相关的组件接口拆分成独立的组件,通过组合的方式进行组装。

  3. 使用 Hooks 来封装相关功能,实现接口的隔离。

根据接口隔离原则的说法,客户端不应该依赖它不需要的接口

首先,我们看一下组件实现接口隔离原则的区别:

为了更好的说明 ISP 所针对的问题,来看一个呈现视频列表的组件:

复制代码
type Video = {
  title: string
  duration: number
  coverUrl: string
}

type Props = {
  items: Array<Video>
}

const VideoList = ({ items }) => {
  return (
    <ul>
      {items.map(item => 
        <Thumbnail 
          key={item.title} 
          video={item} 
        />
      )}
    </ul>
  )
}

Thumbnail 组件的实现如下:

复制代码
type Props = {
  video: Video,
};

const Thumbnail = ({ video }: Props) => {
  return <img src={video.coverUrl} />;
};

Thumbnail 组件非常小并且很简单,但它有一个问题:它希望将完整的视频对象作为 props 传入,但是仅有效地使用其属性之一(coverUrl)。

除了视频,我们还需要渲染直播的缩略图,这两种媒体资源会混合在同一个列表中。

下面来定义直播的类型 LiveStream

复制代码
type LiveStream = {
  name: string
  previewUrl: string
}

这是更新后的 VideoList 组件:

复制代码
type Props = {
  items: Array<Video | LiveStream>,
};

const VideoList = ({ items }) => {
  return (
    <ul>
            
      {items.map((item) => {
        if ("coverUrl" in item) {
          return <Thumbnail video={item} />;
        } else {
          // 直播组件,该怎么写?
        }
      })}
          
    </ul>
  );
};

这时就发现一个问题,我们可以轻松的区分视频和直播对象,但是不能将后者传递给Thumbnail组件,因为VideoLiveStream类型不兼容。它们包含了不同的属性来保存缩略图:视频对象调用coverUrl,直播对象调用previewUrl。这就是使组件依赖了比实际更多的props的原因所在。

下面来重构 Thumbnail 组件以确保它仅依赖于它需要的props

复制代码
type Props = {
  coverUrl: string,
};

const Thumbnail = ({ coverUrl }: Props) => {
  return <img src={coverUrl} />;
};

通过这样修改,现在我们可以使用它来渲染视频和直播的对略图:

复制代码
type Props = {
  items: Array<Video | LiveStream>,
};

const VideoList = ({ items }) => {
  return (
    <ul>
            
      {items.map((item) => {
        if ("coverUrl" in item) {
          return <Thumbnail coverUrl={item.coverUrl} />;
        } else {
          return <Thumbnail coverUrl={item.previewUrl} />;
        }
      })}
          
    </ul>
  );
};

当然,这段代码还可以简化一下:

复制代码
type Props = {
  items: Array<Video | LiveStream>,
};

const VideoList = ({ items }) => {
  return (
    <ul>
            
      {items.map((item) => (
        <Thumbnail
          coverUrl={"coverUrl" in item ? item.coverUrl : item.previewUrl}
        />
      ))}
          
    </ul>
  );
};

接口隔离原则主张最小化系统组件之间的依赖关系,使它们的耦合度降低,从而提高可重用性。

遵循接口隔离原则有助于提高代码的可维护性和可扩展性。在实际开发中,我们应该注重代码的设计和组织,提高代码的可读性和可复用性,并避免不必要的依赖关系。同时注重代码的重用和扩展性,从而提高开发效率和代码质量。

参考资料

  • React documentation. Retrieved from React
相关推荐
爱编程的喵1 小时前
深入理解JSX:从语法糖到React的魔法转换
前端·react.js
xptwop1 小时前
05-ES6
前端·javascript·es6
海底火旺1 小时前
单页应用路由:从 Hash 到懒加载
前端·react.js·性能优化
Heo1 小时前
调用通义千问大模型实现流式对话
前端·javascript·后端
前端小巷子2 小时前
深入 npm 模块安装机制
前端·javascript·面试
深职第一突破口喜羊羊3 小时前
记一次electron开发插件市场遇到的问题
javascript·electron
cypking3 小时前
electron中IPC 渲染进程与主进程通信方法解析
前端·javascript·electron
西陵3 小时前
Nx带来极致的前端开发体验——借助playground开发提效
前端·javascript·架构
江城开朗的豌豆4 小时前
Element UI动态组件样式修改小妙招,轻松拿捏!
前端·javascript·vue.js
float_六七4 小时前
JavaScript:现代Web开发的核心动力
开发语言·前端·javascript