---
title: 开发文档
order: 3
category: pro
---

# PisellFilter 开发文档

## 技术栈

- **React**: 18+
- **TypeScript**: 5+
- **Ant Design**: 5+
- **React Hooks**: useState, useEffect

## 代码结构

```
pisellFilter/
├── index.tsx              # 组件主入口
├── type.ts                # TypeScript 类型定义
└── docs/                  # 组件文档目录
    ├── PisellFilter.md                    # 使用文档
    ├── PisellFilter.$tab-design.md        # 设计文档
    ├── PisellFilter.$tab-dev.md           # 开发文档（本文件）
    └── PisellFilter.$tab-test.md          # 测试文档
```

## 核心实现

### 组件结构

```
const PisellFilter = (props: PisellFilterProps) => {
  const {
    value: originalValue,
    quickFilterMaxLength,
    formFiltersPrefix,
    hiddenQuickFilter = true,
    hiddenOtherFilter = false,
    ...otherProps
  } = props;

  const [value, setValue] = useState<any>({});

  useEffect(() => {
    setValue({
      quickFilter: originalValue?.quickFilter || [],
      otherFilter: originalValue?.otherFilter || [],
    });
  }, [originalValue]);

  return (
    <Form size="large" layout="vertical" {...otherProps}>
      <FilterButton
        value={{
          quickFilter: value.quickFilter,
          otherFilter: value.otherFilter,
        }}
        hiddenQuickFilter={hiddenQuickFilter}
        hiddenOtherFilter={hiddenOtherFilter}
        onChange={setValue}
        quickFilterMaxLength={quickFilterMaxLength || 100}
        formFiltersPrefix={formFiltersPrefix || ''}
      />
    </Form>
  );
};
```

### 设计思路

1. **属性解构**: 将组件属性分为三类

   - 筛选相关：`value`、`quickFilterMaxLength`、`formFiltersPrefix`
   - 显示控制：`hiddenQuickFilter`、`hiddenOtherFilter`
   - 表单属性：透传给 Form 组件

2. **状态管理**:

   - 使用 `useState` 管理内部筛选值
   - 使用 `useEffect` 监听外部值变化并同步

3. **组件嵌套**:

   - Form 提供表单能力
   - FilterButton 实现筛选逻辑

4. **默认值处理**: 为关键属性提供合理的默认值

## 类型定义

```typescript
import { FilterListProps } from '../filter/components/FilterButton/types';

export type PisellFilterProps = FilterListProps & {
  hasForm?: boolean;
};
```

### 类型说明

- **FilterListProps**: 继承自 FilterButton 组件的属性
- **hasForm**: 是否内联挂载 antd Form（组件内部使用 `Form.useForm()`，props 上不再交叉 `FormInstance`）

### FilterListProps 详解

```typescript
type FilterListProps = {
  value?: FilterValueType; // 筛选值
  hiddenQuickFilter?: boolean; // 隐藏快速筛选
  hiddenOtherFilter?: boolean; // 隐藏高级筛选
  onChange?: (value: FilterValueType) => void; // 变化回调
  quickFilterMaxLength: number; // 快速筛选最大长度
  formFiltersPrefix: string; // 表单字段前缀
  renderItem?: (item: any, otherProps?: any) => React.ReactNode; // 自定义渲染
};
```

### FilterValueType 详解

```typescript
type FilterValueType = {
  quickFilter: FilterItemProps[]; // 快速筛选项数组
  otherFilter: FilterItemProps[]; // 高级筛选项数组
};
```

### FilterItemProps 详解

```typescript
type FilterItemProps = {
  type: 'single' | 'input' | 'datePicker' | 'rangePicker' | 'search';
  name?: string | string[]; // 字段名，rangePicker 时为数组
  key: string; // 唯一标识
  props: object; // 传递给筛选组件的属性
  label?: string; // 显示标签
  sort?: boolean; // 是否可排序
  localFilter?: boolean; // 是否本地筛选
  other: Record<string, any>; // 其他配置
  isCustom?: boolean; // 是否自定义
  columnKey?: string; // 列键值
  isHidden?: boolean; // 是否隐藏
};
```

## 依赖组件

### FilterButton 组件

PisellFilter 依赖内部的 `FilterButton` 组件实现核心筛选功能。

**引用路径**: `../filter/components/FilterButton`

**核心属性**:

- `value`: 筛选值对象
- `onChange`: 筛选变化回调
- `hiddenQuickFilter`: 隐藏快速筛选
- `hiddenOtherFilter`: 隐藏高级筛选
- `quickFilterMaxLength`: 快速筛选最大数量
- `formFiltersPrefix`: 表单字段前缀

## 开发注意事项

### 1. 状态同步

组件使用 `useEffect` 同步外部状态：

```
useEffect(() => {
  setValue({
    quickFilter: originalValue?.quickFilter || [],
    otherFilter: originalValue?.otherFilter || [],
  });
}, [originalValue]);
```

**注意点**:

- 使用可选链 `?.` 避免 undefined 错误
- 提供空数组作为默认值
- 依赖项正确设置为 `[originalValue]`

### 2. 默认值处理

```
quickFilterMaxLength={quickFilterMaxLength || 100}
formFiltersPrefix={formFiltersPrefix || ''}
```

**建议**:

- 为数字类型提供合理的默认值
- 为字符串类型提供空字符串默认值
- 避免使用 `undefined` 导致的渲染问题

### 3. 属性透传

```
const {
  value: originalValue,
  quickFilterMaxLength,
  formFiltersPrefix,
  hiddenQuickFilter = true,
  hiddenOtherFilter = false,
  ...otherProps
} = props;
```

**策略**:

- 提取需要特殊处理的属性
- 使用展开运算符透传其他属性
- 注意避免属性冲突

### 4. Form 配置

```
<Form size="large" layout="vertical" {...otherProps}>
```

**说明**:

- `size="large"`: 使用大尺寸表单项，提升移动端体验
- `layout="vertical"`: 垂直布局，标签在上方
- `{...otherProps}`: 支持覆盖默认配置

## 状态管理最佳实践

### 受控模式

```
const [filterValue, setFilterValue] = useState({
  quickFilter: [],
  otherFilter: [],
});

<PisellFilter
  value={filterValue}
  onChange={setFilterValue}
/>
```

### 非受控模式

组件内部维护状态，但不推荐这种方式：

```
<PisellFilter
  quickFilterMaxLength={5}
  formFiltersPrefix="filter_"
/>
```

## 性能优化

### 1. 使用 memo

如果组件频繁重渲染，考虑使用 `React.memo`：

```
export default React.memo(PisellFilter);
```

### 2. 回调优化

使用 `useCallback` 优化回调函数：

```
const handleChange = useCallback((newValue: FilterValueType) => {
  setValue(newValue);
  onChange?.(newValue);
}, [onChange]);
```

### 3. 避免重复渲染

合理使用 `useEffect` 的依赖项：

```
// ✅ 正确
useEffect(() => {
  setValue({
    quickFilter: originalValue?.quickFilter || [],
    otherFilter: originalValue?.otherFilter || [],
  });
}, [originalValue]);

// ❌ 错误 - 缺少依赖项
useEffect(() => {
  setValue({
    quickFilter: originalValue?.quickFilter || [],
    otherFilter: originalValue?.otherFilter || [],
  });
}, []);
```

## 扩展开发

### 添加新的筛选类型

1. 在 `FilterItemProps` 的 `type` 中添加新类型
2. 在 `FilterButton` 组件中实现对应的渲染逻辑
3. 更新文档说明

### 自定义渲染

使用 `renderItem` 属性自定义筛选项渲染：

```
const renderItem = (item: FilterItemProps, otherProps: any) => {
  return (
    <div className="custom-filter-item">
      <span>{item.label}</span>
      {/* 自定义逻辑 */}
    </div>
  );
};

<PisellFilter renderItem={renderItem} />
```

## 调试技巧

### 1. 查看筛选值变化

```
useEffect(() => {
  console.log('Filter value changed:', value);
}, [value]);
```

### 2. 检查属性传递

```
const {
  value: originalValue,
  quickFilterMaxLength,
  formFiltersPrefix,
  ...otherProps
} = props;

console.log('Props:', {
  originalValue,
  quickFilterMaxLength,
  formFiltersPrefix,
  otherProps,
});
```

### 3. 调试 FilterButton

在 FilterButton 组件中添加日志：

```
<FilterButton
  value={{
    quickFilter: value.quickFilter,
    otherFilter: value.otherFilter,
  }}
  onChange={(newValue) => {
    console.log('FilterButton onChange:', newValue);
    setValue(newValue);
  }}
/>
```

## 常见问题

### Q1: 为什么需要内部状态？

**A**: 组件需要在接收外部 `value` 后，进行初始化和默认值处理。内部状态提供了一个缓冲层，避免直接修改外部状态。

### Q2: 如何实现筛选值的持久化？

**A**: 在 `onChange` 回调中将筛选值保存到 localStorage：

```
const handleChange = (newValue: FilterValueType) => {
  setFilterValue(newValue);
  localStorage.setItem('filterValue', JSON.stringify(newValue));
};
```

### Q3: 如何重置筛选？

**A**: 调用 `onChange` 传入空值：

```
const resetFilter = () => {
  onChange?.({
    quickFilter: [],
    otherFilter: [],
  });
};
```

### Q4: 筛选值格式不正确怎么办？

**A**: 添加类型验证和错误处理：

```
useEffect(() => {
  if (!originalValue) return;

  const isValid =
    Array.isArray(originalValue.quickFilter) &&
    Array.isArray(originalValue.otherFilter);

  if (!isValid) {
    console.error('Invalid filter value format');
    return;
  }

  setValue(originalValue);
}, [originalValue]);
```

## 相关资源

- [Ant Design Form API](https://ant.design/components/form-cn/#API)
- [React Hooks 文档](https://react.dev/reference/react)
- [TypeScript 交叉类型](https://www.typescriptlang.org/docs/handbook/2/objects.html#intersection-types)
- [FilterButton 组件源码](../filter/components/FilterButton)
