fix(subtable): should not have a value by default and fix key of table (#2763)
* fix(subtable): should not have a value by default and fix key of table * fix(subtable): fix invalid to set default value
This commit is contained in:
		
							parent
							
								
									8f29fde008
								
							
						
					
					
						commit
						3b76a84605
					
				@ -91,7 +91,7 @@ export const SubTable: any = observer(
 | 
				
			|||||||
                  onClick={() => {
 | 
					                  onClick={() => {
 | 
				
			||||||
                    field.value = field.value || [];
 | 
					                    field.value = field.value || [];
 | 
				
			||||||
                    field.value.push({});
 | 
					                    field.value.push({});
 | 
				
			||||||
                    void field.onInput(field.value);
 | 
					                    field.onInput(field.value);
 | 
				
			||||||
                  }}
 | 
					                  }}
 | 
				
			||||||
                  icon={<PlusOutlined />}
 | 
					                  icon={<PlusOutlined />}
 | 
				
			||||||
                >
 | 
					                >
 | 
				
			||||||
 | 
				
			|||||||
@ -72,9 +72,8 @@ const useParseDefaultValue = () => {
 | 
				
			|||||||
            setDefaultValue(value);
 | 
					            setDefaultValue(value);
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
          // TODO: 可能会因为异步时序问题导致设置默认值无效
 | 
					 | 
				
			||||||
          // eslint-disable-next-line promise/catch-or-return
 | 
					          // eslint-disable-next-line promise/catch-or-return
 | 
				
			||||||
          void Promise.resolve().then(() => {
 | 
					          Promise.resolve().then(() => {
 | 
				
			||||||
            field.setInitialValue(value);
 | 
					            field.setInitialValue(value);
 | 
				
			||||||
          });
 | 
					          });
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -91,7 +90,7 @@ const useParseDefaultValue = () => {
 | 
				
			|||||||
    // 使用防抖,提高性能和用户体验
 | 
					    // 使用防抖,提高性能和用户体验
 | 
				
			||||||
    const run = _.debounce(_run, DEBOUNCE_WAIT);
 | 
					    const run = _.debounce(_run, DEBOUNCE_WAIT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void _run();
 | 
					    _run();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (isVariable(fieldSchema.default)) {
 | 
					    if (isVariable(fieldSchema.default)) {
 | 
				
			||||||
      const variableName = getVariableName(fieldSchema.default);
 | 
					      const variableName = getVariableName(fieldSchema.default);
 | 
				
			||||||
 | 
				
			|||||||
@ -162,13 +162,14 @@ export function isFromDatabase(value: Record<string, any>) {
 | 
				
			|||||||
export const useSubTableSpecialCase = ({ field }) => {
 | 
					export const useSubTableSpecialCase = ({ field }) => {
 | 
				
			||||||
  useEffect(() => {
 | 
					  useEffect(() => {
 | 
				
			||||||
    if (_.isEmpty(field.value)) {
 | 
					    if (_.isEmpty(field.value)) {
 | 
				
			||||||
 | 
					      const value = field.value;
 | 
				
			||||||
      field.value = [{}];
 | 
					      field.value = [{}];
 | 
				
			||||||
      // 因为默认值的解析是异步的,所以下面的代码会优先于默认值的设置,这样就防止了设置完默认值后又被清空的问题
 | 
					      // 因为默认值的解析是异步的,所以下面的代码会优先于默认值的设置,这样就防止了设置完默认值后又被清空的问题
 | 
				
			||||||
      Promise.resolve()
 | 
					      setTimeout(() => {
 | 
				
			||||||
        .then(() => {
 | 
					        if (JSON.stringify(field.value) === '[{}]') {
 | 
				
			||||||
          field.value = [];
 | 
					          field.value = value;
 | 
				
			||||||
        })
 | 
					        }
 | 
				
			||||||
        .catch(console.error);
 | 
					      });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }, []);
 | 
					  }, []);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -6,11 +6,12 @@ import { ArrayField } from '@formily/core';
 | 
				
			|||||||
import { spliceArrayState } from '@formily/core/esm/shared/internals';
 | 
					import { spliceArrayState } from '@formily/core/esm/shared/internals';
 | 
				
			||||||
import { RecursionField, Schema, observer, useField, useFieldSchema } from '@formily/react';
 | 
					import { RecursionField, Schema, observer, useField, useFieldSchema } from '@formily/react';
 | 
				
			||||||
import { action } from '@formily/reactive';
 | 
					import { action } from '@formily/reactive';
 | 
				
			||||||
 | 
					import { uid } from '@formily/shared';
 | 
				
			||||||
import { isPortalInBody } from '@nocobase/utils/client';
 | 
					import { isPortalInBody } from '@nocobase/utils/client';
 | 
				
			||||||
import { useMemoizedFn } from 'ahooks';
 | 
					import { useMemoizedFn } from 'ahooks';
 | 
				
			||||||
import { Table as AntdTable, TableColumnProps } from 'antd';
 | 
					import { Table as AntdTable, TableColumnProps } from 'antd';
 | 
				
			||||||
import { default as classNames, default as cls } from 'classnames';
 | 
					import { default as classNames, default as cls } from 'classnames';
 | 
				
			||||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
 | 
					import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
 | 
				
			||||||
import { useTranslation } from 'react-i18next';
 | 
					import { useTranslation } from 'react-i18next';
 | 
				
			||||||
import { DndContext, useDesignable, useTableSize } from '../..';
 | 
					import { DndContext, useDesignable, useTableSize } from '../..';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
@ -101,12 +102,13 @@ const useTableColumns = (props: { showDel?: boolean; isSubTable?: boolean }) =>
 | 
				
			|||||||
          <DeleteOutlined
 | 
					          <DeleteOutlined
 | 
				
			||||||
            style={{ cursor: 'pointer' }}
 | 
					            style={{ cursor: 'pointer' }}
 | 
				
			||||||
            onClick={() => {
 | 
					            onClick={() => {
 | 
				
			||||||
              void action(() => {
 | 
					              action(() => {
 | 
				
			||||||
                spliceArrayState(field as any, {
 | 
					                spliceArrayState(field as any, {
 | 
				
			||||||
                  startIndex: index,
 | 
					                  startIndex: index,
 | 
				
			||||||
                  deleteCount: 1,
 | 
					                  deleteCount: 1,
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
                field.value.splice(index, 1);
 | 
					                field.value.splice(index, 1);
 | 
				
			||||||
 | 
					                field.initialValue?.splice(index, 1);
 | 
				
			||||||
                return field.onInput(field.value);
 | 
					                return field.onInput(field.value);
 | 
				
			||||||
              });
 | 
					              });
 | 
				
			||||||
            }}
 | 
					            }}
 | 
				
			||||||
@ -231,6 +233,7 @@ export const Table: any = observer(
 | 
				
			|||||||
    const [selectedRow, setSelectedRow] = useState([]);
 | 
					    const [selectedRow, setSelectedRow] = useState([]);
 | 
				
			||||||
    const dataSource = field?.value?.slice?.()?.filter?.(Boolean) || [];
 | 
					    const dataSource = field?.value?.slice?.()?.filter?.(Boolean) || [];
 | 
				
			||||||
    const isRowSelect = rowSelection?.type !== 'none';
 | 
					    const isRowSelect = rowSelection?.type !== 'none';
 | 
				
			||||||
 | 
					    const defaultRowKeyMap = useRef(new Map());
 | 
				
			||||||
    let onRow = null,
 | 
					    let onRow = null,
 | 
				
			||||||
      highlightRow = '';
 | 
					      highlightRow = '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -339,8 +342,29 @@ export const Table: any = observer(
 | 
				
			|||||||
      };
 | 
					      };
 | 
				
			||||||
    }, [field, onRowDragEnd, dragSort]);
 | 
					    }, [field, onRowDragEnd, dragSort]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 为没有设置 key 属性的 record 生成一个唯一的 key
 | 
				
			||||||
 | 
					     * 1. rowKey 的默认值是 “key”,所以先判断有没有 record.key;
 | 
				
			||||||
 | 
					     * 2. 如果没有就生成一个唯一的 key,并以 record 的值作为索引;
 | 
				
			||||||
 | 
					     * 3. 这样下次就能取到对应的 key 的值;
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * 这里有效的前提是:数组中对应的 record 的引用不会发生改变。
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param record
 | 
				
			||||||
 | 
					     * @returns
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    const defaultRowKey = (record: any) => {
 | 
					    const defaultRowKey = (record: any) => {
 | 
				
			||||||
      return field.value?.indexOf?.(record);
 | 
					      if (record.key) {
 | 
				
			||||||
 | 
					        return record.key;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (defaultRowKeyMap.current.has(record)) {
 | 
				
			||||||
 | 
					        return defaultRowKeyMap.current.get(record);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const key = uid();
 | 
				
			||||||
 | 
					      defaultRowKeyMap.current.set(record, key);
 | 
				
			||||||
 | 
					      return key;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const getRowKey = (record: any) => {
 | 
					    const getRowKey = (record: any) => {
 | 
				
			||||||
 | 
				
			|||||||
@ -1 +1 @@
 | 
				
			|||||||
export const DEBOUNCE_WAIT = 500;
 | 
					export const DEBOUNCE_WAIT = 300;
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user