需求
最近在写启明的一个需求,其中的某个界面需要对于一个Filter组件进行封装,
最近两天一直在做这个事情,现在终于算是完成了一个比较满意的架构设计,于是写下这篇来分享一下!
设计
项目整体设计
这个项目的整体数据处理逻辑大概是这样的
[store] -> [hooks] -> [components] -> [pages]
store中的数据如果想要展示在页面上,就必须经过hook的处理,所有的逻辑
都尽量封装到hook中,这样能保证处理位置的一致性,最大的一个好处是我只需要知道初始数据和最终数据的
数据结构即可,至于是怎么转换,获取的等,我们一概不需要去关心,这就是非常让人舒服的事情了,尤其是对于团队合作来说,
同事就可以直接使用已经经过处理的数据了。
Filter组件的设计
这个组件主要包含两个部分
- 上部分是一个
search bar,这个search bar的左部分是Input,右部分就是一个Type下拉框和Btn两部分。, - 下部分是一个
Filter List,需要支持不同的数据类型,比如string[],Record<string, Record<string, string[]>>

需要注意的是下拉框的设计,不过这是组件样式的问题了,这里先不说,而是主要说逻辑的问题
type FilterOptionsType = Record<
string,
string[] | Record<string, Record<string, string[]>>
>;
// 第一个string是类似于'赛事分类'、'赛事名称'这样的值
// string[] | Record<string, Record<string, string[]>>就需要每个类型单独处理一下render的样式了
Filter的设计是这样的
from hook1(config hook)
-> filter config
-> filter
-> hook2(form data hook)
-> collect user selected data
-> hook3(api effect request hook)
-> request data from backend
-> components
对于Filter本身来说
interface FilterProps<T extends SearchType> {
// 是否需要设置搜索类型 若设置searchTypeOptions则为true
searchTypeOptions?: string[];
initialData: Partial<T>;
filterOptions: FilterOptionsType;
// 回调函数,当用户选择发生变化时调用
onFilterChange: (searchData: T) => void;
}
用户选择的选项直接会被转换成后端所需要的search type,其实最初我的思路并非如此,
刚开始是这样的
interface FilterProps<T extends SearchType> {
// 是否需要设置搜索类型 若设置searchTypeOptions则为true
searchTypeOptions?: string[];
initialData: Partial<T>;
filterOptions: FilterOptionsType;
adapter: (data: FilterOptionsType) => SearchType;
// 回调函数,当用户选择发生变化时调用
onFilterChange: (searchData: T) => void;
}
但是这样的话又会比较麻烦,体现在:filterOptions不是用户的选项数据结构,而是配置项的数据结构,所以这样就需要一个从FilterOptionsType=>SearchType的Adapter函数,
这个函数需要递归处理FilterOptionsType的内容,所以这个Adapter会比较复杂,而且并不是很合理,既然用户进行了选择,为什么不直接转成最终后端需要的呢,再转一遍FilterOptionsType很多此一举。