React视图和逻辑分离,容器组件和展示组件

179 阅读3分钟

我们在做后管类项目时,常常会和表单打交道,编辑状态和创建状态常常会令人头疼,看样例,有图有真相。

这是一个VUE的项目中的一个创建套餐和编辑套餐的页面1707行!,下面样式部分还没算上。 image.png

页面使用isEditing属性来区分编辑还是新建,它也是付出了很多。

image.png

这就是典型的编辑、新建页面加逻辑在一把梭啊,因为这个页面在我入职的时候就已经有了,所以只能动上面的代码,我是一动不敢动啊,就怕搞出bug了。每一次有需求要动的时候,我都在祈祷不要动套餐部分,不要落到我头上 (但是还是没有那么幸运啊,有幸改了一次,很难受,一点不让我乘凉),1707行真的很难改啊!!!

好消息是,它走上正轨了,不用我们动了!

所以,在新的项目中我写的部分,文件通常都在200多行,基本不会过400行,只要颗粒度一细,文件大小自然就下来了。但是有时候也不能过度的要颗粒度。

今天来谈一下经典的React设计模式容器组件和展示组件,这种模式有助于提高代码的可读性和可维护性,也是分分钟解决上面的屎山代码。也是我在项目中经常使用的一种方式,可以将逻辑和UI分别统一起来一起处理。

正文

什么是容器组件和展示组件

展示组件(Presentational Components)

  • 主要负责UI的渲染。
  • 通常是无状态的函数组件。
  • 通过props接收数据和回调函数。
  • 尽可能避免使用状态和逻辑。

容器组件(Container Components)

  • 主要负责业务逻辑和数据处理。
  • 通常是有状态的组件。
  • 通过props将数据和回调函数传递给展示组件。
  • 处理与Redux或其他状态管理工具的交互。

如何使用容器组件和展示组件

不使用容器组件和展示组件的代码是什么样子,不用再演示了吧,自己去看看项目中1000多行的屎山代码就可以了。接下来步入正题。

大致代码就是下面这个样子,外面就是容器组件,主要负责业务逻辑和数据处理。InfoShow就是展示组件,只负责UI的渲染,通过props接收数据和回调函数改变数据。同理要改变容器组件里面的什么展示什么不展示,是否disable等等,都可以通过props传递状态。

export default function Index() {
  const [info, setInfo] = useState<Info>({
    name: '',
    time: '',
    peopleList: [],
  });

  useEffect(() => {
    //如果是编辑状态,则从服务器获取数据
  }, []);

  return (
    <>
      <InfoShow
        info={info}
        handleChange={(data: Partial<Info>) => {
          setInfo({ ...info, ...data });
        }}
      />
    </>
  );
}

还可以使用hook进一步的优化。

如何通过 React 钩子取代容器组件

自 React 16.8.0 以来,借助函数组件和钩子构建和开发组件变得更加容易。

我们将利用这一能力,用钩子替换容器组件。可以进一步的优化代码,使Index不再是容器组件,而是起到一个桥梁的作用。真正起容器组件作用的是useInfo,进一步的细化颗粒度。

//useInfo.ts
import React, { useCallback, useEffect, useState } from 'react';
import { Info } from '../type';

export default function Index() {
  const [info, setInfo] = useState<Info>({
    name: '',
    time: '',
    peopleList: []
  })

  const handleChange = useCallback((data: Partial<Info>) => {
    setInfo(prev => ({ ...prev, ...data }))
  }, [])

  useEffect(() => {
    //如果是编辑状态,则从服务器获取数据
  }, []);

  return {
    info,
    setInfo,
    handleChange
  }
}
export default function Index() {
  const { info, handleChange } = useInfo();

  return (
    <>
      <InfoShow info={info} handleChange={handleChange} />
    </>
  );
}

结语

感兴趣的可以去试试,一个很不错的React设计模式。