前端整洁架构 React+TypeScript 实现

1,935 阅读2分钟

参考资料

github.com/phodal/clea…

github.com/bespoyasov/…

github.com/falsy/react…

www.cnblogs.com/yjf512/arch…

整洁架构之道

前言

个人能力有限,如有错误望指正。

我这个实现架构还是有不少的问题:

  1. 未使用依赖注入

  2. 各个模块依赖抽象

  3. 职责划分问题

  4. 最严的测试(😓实在是太忙)

当你在阅读这篇文章时,我假设你已经看完了 phodal Clean Frontend Architecture:整洁前端架构

且了解 bob 大叔设计的整洁架构

domain

我们先来看下目录结构,目录结构参考clean-frontend

 ├─src
    ├─code
    ├─domain
    ├─features
    ├─pages
    ├─presentation
    ├─router
    └─stores

phodal 文章有讲到,这里我在做赘述。

router: 路由

stores: 状态管理

那么我们再来看下 domain

├─domain
    ├─admin
    │  ├─adapter       // 适配器
    │  ├─model         // 模型
    │  ├─repositories  // 容器
    │  │  └─mapper     // 字段映射
    │  └─usecase       // 用例

基本上一致,只是多了一个 adapter(适配器)。因为在 phodal 设计的架构中,我一直很好奇为什么没有 adapter(适配器)。

我认为是 angularservice 承担了adapter的职责。

model

entity 实体是我们请求时接口返回给我们的类型。

model 这个model则是我们UI要使用的数据类型,类型与entity会有细微出入。

repositories

我更喜欢叫 接口仓库,职责就是负责请求api 接口

mapper 负责将接口请求到的entity转换成 UI 所需要的 model 数据。

adapter

我们再来看一句话:

这一层的软件结构的目的就是进行数据的转换,将便于用户实例和实体层操作的数据结构变化成为最便于外部结构(比如数据库或者 Web)操作的数据结构。比如 GUI 的 MVC 结构,表现器、视图器、控制器都是属于这个结构的。这层很可能是通过控制器将数据结构传给用户实例层,并且返回数据给表现器,视图器。

简单来说就是 可以通过adapter将数据传递给 UI 层。

tips: repositories下的 mapper 也是 adapter

所以我们可以将 reacthook封装成adapter

其他的我们就可以直接套用 phodal 设计的规则来编写业务代码。

usecase

负责 repositories 调用 and mapper映射。

各层依赖关系

presentation <- adapter <- usecase <- repositories <- model

adapter

在我这个架构设计中,adapter只是个普普通通的 hook

adapter 与 react context 结合

当我用context的时候,习惯一股脑地所有方法全部扔 context中。

这样会使context 职责过多,可以试着context 只放 state, 一些业务函数呢可以放到adapter, provider则只需要暴露出状态和set方法。

export const UserProvider = ({ children }) => {
  const [user, setUser] = useState<UserModel>()
  const [activeId, setActiveId] = useState<string>()
  const [userAction, setUserAction] = useState<UserActionDetail>({} as UserActionDetail)

  const value = useMemo(
    () => ({
      user,
      activeId,
      userAction,
      updateUser: setUser,
      updateUserAction: setUserAction,
      updateActiveId: setActiveId
    }),
    [user, userAction, activeId, setUser, setUserAction, setActiveId]
  )

  return <UserContext.Provider value={value}>{children}</UserContext.Provider>
}
export const useGetUserActionListAdapter = () => {
  const { activeId, updateUserAction, updateActiveId } = useUserContext()

  const handleSomeThinkg = userAction => {
    updateUserAction(userAction)
    updateActiveId(0)
  }
}

在对应的 adapter使用该方法,最终在页面中使用我们自定义的hook

结尾

架构只是毛坯房,房子装修的好看不好看,决定这一切的还是"设计团队"、"装修团队"等。不要一上来就是整洁架构,因为整洁架构不是银弹!

github