Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/examples/expandedRowRender.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,9 @@ const Demo = () => {
rowExpandable,
expandIconColumnIndex: expandIconPosition ? 1 : null,
fixed: fixExpand,
forceRender: record => {
return record?.key === 0;
},
Comment on lines +149 to +151
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This arrow function can be simplified to a single line for better readability.

          forceRender: record => record?.key === 0,

}}
scroll={{ x: fixColumns || scrollX ? 2000 : null, y: fixHeader ? 300 : null }}
data={data}
Expand Down
11 changes: 10 additions & 1 deletion src/Body/BodyRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export interface BodyRowProps<RecordType> {
colSpan: number;
sticky: number;
};
forceRender?: boolean | ((record: RecordType, index: number) => boolean);
}
Comment on lines +34 to 35
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

统一 forceRender 签名、去除重复调试渲染与细节优化

  • 类型一致性:此处回调签名为 (record, index) => boolean,而 TableContext / ExpandableConfig 目前为单参数。建议统一为“带可选 index”的形式,避免调用/声明不一致。
  • 细节优化:
    • devRenderTimes(props) 在文件内被调用了两次(行 123 与 169);保留一次即可。
    • shouldForceRender 是本地常量,无需可选链调用,直接 shouldForceRender()
 export interface BodyRowProps<RecordType> {
-  forceRender?: boolean | ((record: RecordType, index: number) => boolean);
+  // 与对外 API / Context 对齐,index 可选
+  forceRender?: boolean | ((record: RecordType, index?: number) => boolean);
 }

@@
-  if (process.env.NODE_ENV !== 'production') {
-    devRenderTimes(props);
-  }
+  // 调试渲染计数仅保留一次调用
@@
-  const shouldForceRender = () => {
+  const shouldForceRender = () => {
     if (typeof forceRender === 'function') {
-      return forceRender(record, index);
+      return forceRender(record, index);
     }
     return !!forceRender;
   };
@@
-  if (rowSupportExpand && (expandedRef.current || expanded || shouldForceRender?.())) {
+  if (rowSupportExpand && (expandedRef.current || expanded || shouldForceRender())) {

另需在文档中说明回调的 index 语义(展平后的行序号 vs 源数据下标),以免使用方误解。

Also applies to: 142-143, 162-168, 236-237


🏁 Script executed:

#!/bin/bash
# Gather information about BodyRow.tsx and related type definitions

echo "=== Checking BodyRow.tsx content (key lines) ==="
cat src/Body/BodyRow.tsx | head -250

echo -e "\n=== Searching for devRenderTimes calls ==="
rg -n "devRenderTimes" src/Body/BodyRow.tsx

echo -e "\n=== Searching for TableContext definition ==="
fd -e ts -e tsx | xargs grep -l "TableContext" | head -5

echo -e "\n=== Searching for ExpandableConfig definition ==="
fd -e ts -e tsx | xargs grep -l "ExpandableConfig" | head -5

Length of output: 7681


🏁 Script executed:

#!/bin/bash
# Search for forceRender definitions in TableContext and ExpandableConfig

echo "=== TableContext definition for forceRender ==="
rg -n "forceRender" src/context/TableContext.tsx -A 2 -B 2

echo -e "\n=== ExpandableConfig definition ==="
rg -n "ExpandableConfig" src/interface.ts -A 10 -B 2

echo -e "\n=== Expand hook definition ==="
rg -n "forceRender" src/hooks/useExpand.ts -A 2 -B 2

echo -e "\n=== Table.tsx for forceRender ==="
rg -n "forceRender" src/Table.tsx -A 2 -B 2

Length of output: 1405


🏁 Script executed:

#!/bin/bash
# Verify what index parameter represents and check ExpandableConfig for forceRender

echo "=== Check if ExpandableConfig has forceRender ==="
rg -n "interface ExpandableConfig" src/interface.ts -A 25

echo -e "\n=== Verify index usage context in BodyRow ==="
rg -n "index" src/Body/BodyRow.tsx | head -20

Length of output: 1847


统一 forceRender 签名、去除重复调试渲染与细节优化

验证结果确认以下问题:

  • 类型签名不一致TableContext(行56)和 ExpandableConfig(行270)中 forceRender 为单参数 (record: RecordType) => boolean,而 BodyRow.tsx(行34-35)添加了 index 参数。建议统一为"带可选 index"的形式。
  • 重复调试调用devRenderTimes(props) 在行124和170被调用两次,应保留其中一次。
  • 不必要的可选链:行237的 shouldForceRender?.() 应改为 shouldForceRender(),因为这是本地常量。
 export interface BodyRowProps<RecordType> {
-  forceRender?: boolean | ((record: RecordType, index: number) => boolean);
+  forceRender?: boolean | ((record: RecordType, index?: number) => boolean);
 }

@@  (行 123-125)
-  if (process.env.NODE_ENV !== 'production') {
-    devRenderTimes(props);
-  }
+  // 调试渲染计数仅保留一次调用
@@  (行 167-172)
   const shouldForceRender = () => {
     if (typeof forceRender === 'function') {
       return forceRender(record, index);
     }
     return !!forceRender;
   };

@@  (行 237)
-  if (rowSupportExpand && (expandedRef.current || expanded || shouldForceRender?.())) {
+  if (rowSupportExpand && (expandedRef.current || expanded || shouldForceRender())) {

建议同步更新 TableContextExpandableConfigforceRender 类型定义,以保持接口一致性。

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/Body/BodyRow.tsx around lines 34-35, the forceRender signature includes
an extra index parameter causing type inconsistency with other definitions;
change it to (record: RecordType, index?: number) => boolean to accept an
optional index, remove the duplicated devRenderTimes(props) call so it only
executes once (keep the most appropriate invocation between lines ~124 and
~170), replace the unnecessary optional chaining at line ~237 from
shouldForceRender?.() to shouldForceRender(), and then sync the updated
forceRender signature in TableContext and ExpandableConfig type definitions to
maintain a consistent interface.


// ==================================================================================
Expand Down Expand Up @@ -138,6 +139,7 @@ const BodyRow = <RecordType extends { children?: readonly RecordType[] }>(
cellComponent,
scopeCellComponent,
expandedRowInfo,
forceRender,
} = props;

const rowInfo = useRowInfo(record, rowKey, index, indent);
Expand All @@ -157,6 +159,13 @@ const BodyRow = <RecordType extends { children?: readonly RecordType[] }>(
const expandedRef = React.useRef(false);
expandedRef.current ||= expanded;

const shouldForceRender = () => {
if (typeof forceRender === 'function') {
return forceRender(record, index);
}
return !!forceRender;
};

if (process.env.NODE_ENV !== 'production') {
devRenderTimes(props);
}
Expand Down Expand Up @@ -224,7 +233,7 @@ const BodyRow = <RecordType extends { children?: readonly RecordType[] }>(

// ======================== Expand Row =========================
let expandRowNode: React.ReactElement<ExpandedRowProps>;
if (rowSupportExpand && (expandedRef.current || expanded)) {
if (rowSupportExpand && (expandedRef.current || expanded || shouldForceRender?.())) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The optional chaining ?.() is unnecessary here as shouldForceRender is a function declared in the component's scope and will always be defined. You can call it directly with shouldForceRender().

Suggested change
if (rowSupportExpand && (expandedRef.current || expanded || shouldForceRender?.())) {
if (rowSupportExpand && (expandedRef.current || expanded || shouldForceRender())) {

const expandContent = expandedRowRender(record, index, indent + 1, expanded);

expandRowNode = (
Expand Down
3 changes: 3 additions & 0 deletions src/Body/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const Body = <RecordType,>(props: BodyProps<RecordType>) => {
styles,
expandedRowOffset = 0,
colWidths,
forceRender
} = useContext(TableContext, [
'prefixCls',
'getComponent',
Expand All @@ -50,6 +51,7 @@ const Body = <RecordType,>(props: BodyProps<RecordType>) => {
'expandedRowOffset',
'fixedInfoList',
'colWidths',
'forceRender'
]);
const { body: bodyCls = {} } = classNames || {};
const { body: bodyStyles = {} } = styles || {};
Expand Down Expand Up @@ -111,6 +113,7 @@ const Body = <RecordType,>(props: BodyProps<RecordType>) => {
indent={indent}
// Expanded row info
expandedRowInfo={expandedRowInfo}
forceRender={forceRender}
/>
);
});
Expand Down
3 changes: 3 additions & 0 deletions src/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -892,6 +892,7 @@ const Table = <RecordType extends DefaultRecordType>(
expandableType,
expandRowByClick: expandableConfig.expandRowByClick,
expandedRowRender: expandableConfig.expandedRowRender,
forceRender: expandableConfig.forceRender,
expandedRowOffset: expandableConfig.expandedRowOffset,
onTriggerExpand,
expandIconColumnIndex: expandableConfig.expandIconColumnIndex,
Expand Down Expand Up @@ -953,6 +954,8 @@ const Table = <RecordType extends DefaultRecordType>(
onTriggerExpand,
expandableConfig.expandIconColumnIndex,
expandableConfig.indentSize,
expandableConfig.forceRender,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This dependency expandableConfig.forceRender is redundant because the entire expandableConfig object is already included as a dependency on the next line. Including the whole object ensures that any change to its properties, including forceRender, will trigger the useMemo hook.

expandableConfig,
emptyNode,

// Column
Expand Down
1 change: 1 addition & 0 deletions src/context/TableContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export interface TableContextProps<RecordType = any> {
expandableType: ExpandableType;
expandRowByClick: boolean;
expandedRowRender: ExpandedRowRender<RecordType>;
forceRender?: boolean | ((record: RecordType) => boolean);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The type for forceRender is inconsistent with its usage in BodyRow.tsx, which passes both record and index to the function. To maintain consistency and allow developers to use the row index, the type should be boolean | ((record: RecordType, index: number) => boolean).

Suggested change
forceRender?: boolean | ((record: RecordType) => boolean);
forceRender?: boolean | ((record: RecordType, index: number) => boolean);

expandIcon: RenderExpandIcon<RecordType>;
Comment on lines +56 to 57
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

上下文类型与对外接口对齐(允许可选 index)

为与 ExpandableConfig.forceRenderBodyRowProps.forceRender 一致,建议将 TableContextProps.forceRender 的函数签名统一为带可选 index:

-  forceRender?: boolean | ((record: RecordType) => boolean);
+  forceRender?: boolean | ((record: RecordType, index?: number) => boolean);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
forceRender?: boolean | ((record: RecordType) => boolean);
expandIcon: RenderExpandIcon<RecordType>;
forceRender?: boolean | ((record: RecordType, index?: number) => boolean);
expandIcon: RenderExpandIcon<RecordType>;
🤖 Prompt for AI Agents
In src/context/TableContext.tsx around lines 56 to 57, update the
TableContextProps.forceRender function signature to match
ExpandableConfig.forceRender and BodyRowProps.forceRender by adding an optional
index parameter: change the function type from (record: RecordType) => boolean
to (record: RecordType, index?: number) => boolean; then update any related
usages and type imports in this file (and exported interfaces if any) to accept
and pass the optional index where applicable so the public API is consistent.

onTriggerExpand: TriggerEventHandler<RecordType>;
expandIconColumnIndex: number;
Expand Down
1 change: 1 addition & 0 deletions src/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ export interface ExpandableConfig<RecordType> {
columnWidth?: number | string;
fixed?: FixedType;
expandedRowOffset?: number;
forceRender?: boolean|((record: RecordType) => boolean);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The type definition for forceRender is missing the index parameter in its function signature. In BodyRow.tsx, this function is called with both record and index. To ensure type consistency and provide the index to the user, the signature should be (record: RecordType, index: number) => boolean. Also, adding a space around | would improve code style consistency.

Suggested change
forceRender?: boolean|((record: RecordType) => boolean);
forceRender?: boolean | ((record: RecordType, index: number) => boolean);

}
Comment on lines +270 to 271
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

对外 API 的函数签名需要统一(建议允许可选 index 参数)

当前 ExpandableConfig<RecordType>.forceRender 定义为 boolean | ((record: RecordType) => boolean),而在 BodyRowProps 中使用的是 (record, index) => boolean。为避免用户在传入 (record, index) 时的类型不一致,并与组件内部调用保持一致,建议将公共类型统一为带可选 index:

-  forceRender?: boolean|((record: RecordType) => boolean);
+  // 与 BodyRow / TableContext 对齐,允许按行下标做条件判断
+  forceRender?: boolean | ((record: RecordType, index?: number) => boolean);

同时顺便对联合类型两侧加空格,保持代码风格一致。

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
forceRender?: boolean|((record: RecordType) => boolean);
}
// 与 BodyRow / TableContext 对齐,允许按行下标做条件判断
forceRender?: boolean | ((record: RecordType, index?: number) => boolean);
}
🤖 Prompt for AI Agents
In src/interface.ts around lines 270-271, the public API type for
ExpandableConfig<RecordType>.forceRender is currently boolean|((record:
RecordType) => boolean) which mismatches BodyRowProps usage of (record, index)
=> boolean; update the type to boolean | ((record: RecordType, index?: number)
=> boolean) so callers can optionally accept index and keep internal calls
consistent, and add spaces around the union operator to match code style; also
verify BodyRowProps uses the same (record, index?: number) => boolean signature.


// =================== Render ===================
Expand Down