浏览代码

fix: Table onChange filters is empty when onFilter is not passing #1572 (#1619)

Co-authored-by: shijia.me <[email protected]>
Shi Jia 2 年之前
父节点
当前提交
95151d6591

+ 12 - 0
cypress/e2e/table.spec.js

@@ -173,4 +173,16 @@ describe('table', () => {
         cy.get('.semi-table-row-cell').eq(2).should('not.have.attr', 'title');
         cy.get('.semi-table-row-cell').eq(3).should('not.have.attr', 'title');
     });
+
+    it('fixed onChange filter incorrect, when setting defaultFilteredValue & without onFilter', () => {
+        cy.visit('http://localhost:6006/iframe.html?id=table--fix-on-change&viewMode=story', {
+            onBeforeLoad(win) {
+                cy.stub(win.console, 'log').as('consoleLog'); // 测试时用到控制台的前置步骤
+            },
+        });
+
+        cy.get('.semi-table-column-sorter').eq(1).click();
+        // filters 长度应该为 1
+        cy.get('@consoleLog').should('be.calledWith', 1);
+    });
 });

+ 7 - 10
packages/semi-foundation/table/foundation.ts

@@ -135,9 +135,10 @@ class TableFoundation<RecordType> extends BaseFoundation<TableAdapter<RecordType
      * init filteredValue of filtering column, use defaultFilteredValue or [] when it is undefined
      */
     static initFilteredValue(column: BaseColumnProps<unknown>) {
-        const { defaultFilteredValue, filteredValue, onFilter } = column;
-        const hasFilter = isFunction(onFilter);
-        if (hasFilter && isUndefined(filteredValue)) {
+        const { defaultFilteredValue, filteredValue } = column;
+        // There may be cases where onFilter is empty, such as server-side filtering
+        // Because filterValue affects the output of filters, it needs to be initialized here
+        if (isUndefined(filteredValue)) {
             if (Array.isArray(defaultFilteredValue) && defaultFilteredValue.length) {
                 column.filteredValue = defaultFilteredValue;
             } else {
@@ -250,13 +251,6 @@ class TableFoundation<RecordType> extends BaseFoundation<TableAdapter<RecordType
     getFilteredSortedDataSource(dataSource: RecordType[], queries: BaseColumnProps<RecordType>[]) {
         const filteredDataSource = this.filterDataSource(dataSource, queries.filter(
             query => {
-                /**
-                 * 这里无需判断 filteredValue 是否为数组,初始化时它是 `undefined`,点击选择空时为 `[]`
-                 * 初始化时我们应该用 `defaultFilteredValue`,点击后我们应该用 `filteredValue`
-                 * 
-                 * There is no need to judge whether `filteredValue` is an array here, because it is `undefined` when initialized, and `[]` when you click to select empty
-                 * When initializing we should use `defaultFilteredValue`, after clicking we should use `filteredValue`
-                 */
                 const currentFilteredValue = query.filteredValue ? query.filteredValue : query.defaultFilteredValue;
                 return (
                     isFunction(query.onFilter) &&
@@ -683,6 +677,9 @@ class TableFoundation<RecordType> extends BaseFoundation<TableAdapter<RecordType
         return this.getState('pagination') || {};
     }
 
+    /**
+     * Filters are considered valid if filteredValue exists
+     */
     _getAllFilters(queries?: BaseColumnProps<RecordType>[]) {
         queries = queries || this.getState('queries');
         const filters: BaseChangeInfoFilter<RecordType>[] = [];

+ 88 - 0
packages/semi-ui/table/_story/v2/FixOnChange/index.tsx

@@ -0,0 +1,88 @@
+import React, { useState, useEffect, useMemo } from 'react';
+import { Table, Avatar } from '@douyinfe/semi-ui';
+import { ColumnProps } from '../../../interface';
+
+/**
+ * 修复第一列 onFilter 未传时,点击第二列的 sorter,onChange filters 为空问题
+ */
+function App() {
+    const [dataSource, setData] = useState([]);
+
+    const scroll = useMemo(() => ({ y: 300 }), []);
+
+    const columns: ColumnProps[] = [
+        {
+            title: '标题',
+            dataIndex: 'name',
+            width: 400,
+            filters: [
+                {
+                    text: 'Semi Design 设计稿',
+                    value: 'Semi Design 设计稿',
+                },
+                {
+                    text: 'Semi Pro 设计稿',
+                    value: 'Semi Pro 设计稿',
+                },
+            ],
+            // onFilter: (value, record) => record.name.includes(value),
+            sorter: (a, b) => a.name.length - b.name.length > 0 ? 1 : -1,
+            defaultFilteredValue: ['Semi Pro 设计稿'],
+        },
+        {
+            title: '大小',
+            dataIndex: 'size',
+            sorter: (a, b) => a.size - b.size > 0 ? 1 : -1,
+            render: (text) => `${text} KB`
+        },
+        {
+            title: '所有者',
+            dataIndex: 'owner',
+            render: (text, record, index) => {
+                return (
+                    <div>
+                        <Avatar size="small" color={record.avatarBg} style={{ marginRight: 4 }}>{typeof text === 'string' && text.slice(0, 1)}</Avatar>
+                        {text}
+                    </div>
+                );
+            }
+
+        }
+    ];
+
+    const getData = (total) => {
+        const data = [];
+        for (let i = 0; i < total; i++) {
+            const isSemiDesign = i % 2 === 0;
+            const randomNumber = (i * 1000) % 199;
+            data.push({
+                key: '' + i,
+                name: isSemiDesign ? `Semi Design 设计稿${i}.fig` : `Semi Pro 设计稿${i}.fig`,
+                owner: isSemiDesign ? '姜鹏志' : '郝宣',
+                size: randomNumber,
+                avatarBg: isSemiDesign ? 'grey' : 'red'
+            });
+        }
+        return data;
+    };
+
+    const handleChange = (options) => {
+        // do not modify console
+        // test with Cypress
+        console.log(options.filters.length);
+    };
+
+    useEffect(() => {
+        const data = getData(46);
+        setData(data);
+    }, []);
+
+    return (
+        <div>
+            <Table columns={columns} dataSource={dataSource} scroll={scroll} onChange={handleChange} />
+        </div>
+    );
+}
+
+App.storyName = 'fix onChange #1572';
+export default App;

+ 2 - 1
packages/semi-ui/table/_story/v2/index.js

@@ -18,4 +18,5 @@ export { default as Zebra } from './zebra';
 export { WordBreakNormalTable, WordBreakFixedTable } from './FeatWordBreak';
 export { EllipsisNormalTable, EllipsisFixedTable, ShowTitleTable } from './FeatEllipsis';
 export { default as Fixed1556 } from './Fixed1556';
-export { default as FixedColumnAlign } from './FixedColumnAlign';
+export { default as FixedColumnAlign } from './FixedColumnAlign';
+export { default as FixOnChange } from './FixOnChange';