ant-design / ant-design/pro-components
🐛[BUG]切换tab值并调用protable的tableFormRef.current.submit()方法,request回调执行次数和submit调用次数不一致,导致数据展示错误
- Dominant language
- TypeScript
- Stars
- 4.8k
- Forks
- 1.4k
- Avg merge
- 10h 44m
- Merged PRs (30d)
- 3
Description
### 🐛 bug 描述
切换tab值并调用protable的tableFormRef.current.submit()方法,request回调执行次数和submit调用次数不一致,导致数据展示错误
### 📷 复现步骤
进入页面先点击图1中,标号2的tab,然后**快速**切换:标号1tab,标号2tab,标号1tab,通过toolbar 定义的menu的onChange来手动设置menu的activeKey并调用tableFormRef.current.submit()方法,结果request只调用了两次,最后标号1的tab的现实的数据是标号2tab请求的数据结果,第三次的请求没有发出去
### 🏞 期望结果
期望的正确结果应该是每次手动调用tableFormRef.current.submit(),都会发起新的请求,tab展示对应请求的结果
### 💻 复现代码
import React, { useEffect, useState, useRef, useCallback } from 'react'
import PropTypes from 'prop-types'
import { Button } from 'antd'
import { decamelizeKeys } from 'humps'
import { get, throttle } from 'lodash'
import { CheckPerm } from 'permissions'
import qs from 'query-string'
import ProTable from '@ant-design/pro-table'
import { compose } from '@bit/redine'
import { transformTableQuery } from '@kfe/ecom-antd'
import { withUrlQuery } from '@kfe/ecom-hocs'
import common from 'modules/common'
import {
COMMISSION_TAB,
COMMISSION_TAB_MAP,
COMMISSION_STATUS
} from '../../../constans'
import { transformDate, caculateDate } from '../../../utils'
import CheckoutDate from '../components/checkoutDate'
import getColumns from '../components/columns'
import useTagColumns from '../components/useTagColumns'
import commission from '../modules/commission'
import CommissionTableConfig from './CommissionTableConfig'
// 操作状态-处理中
const PENDING_STTAUS = 2
let globalIndex1 = 0
const CommisionList = ({
loadCommissionList,
getTeamList,
isLoadingCommisionList,
downloadCommissionList,
getCommisionTags,
changeStatus
}) => {
const [selectedRowKeys, setSelectedRowKeys] = useState([])
const [activeTabKey, setActiveTabKey] = useState(COMMISSION_TAB_MAP.CHECK)
// 业务团队
const [teamList, setTeamList] = useState([])
const tableFormRef = useRef()
const tableListRef = useRef()
// 备注:审核 / 批量审核 / 结算 / 批量结算 / tab 切换
const reloadTable = useCallback(() => {
setSelectedRowKeys([])
tableFormRef.current.submit()
}, [])
// 标签搜索 & 标签组名称
const { getTagColumns, tagGroupNames } = useTagColumns(getCommisionTags)
// 处理标签参数
const handelTagParam = useCallback(
(params = {}) => {
tagGroupNames.forEach((groupName) => {
const tagMap = params[groupName]
if (!tagMap) return
const tags = Object.keys(tagMap).reduce((pre, name) => {
const tagList = Array.isArray(tagMap[name])
? tagMap[name].map((tag) => `${name}__${tag}`)
: []
return [...pre, ...tagList]
}, [])
params[`edu_${groupName}`] = tags.join(',')
delete params[groupName]
})
return params
},
[tagGroupNames]
)
// 处理 form 表单参数
const handleParam = (params = {}) => {
return decamelizeKeys(
transformTableQuery({
...handelTagParam(params),
commission_group_status: COMMISSION_STATUS[activeTabKey],
...transformDate(
params.commission_group_date_range?.[0],
params.commission_group_date_range?.[1]
)
})
)
}
// 携带标签筛选信息更新分佣状态
const changeStatusWithTag = useCallback(
(query, callback) => {
const params = {}
tagGroupNames.forEach((name) => {
params[name] = tableFormRef?.current?.getFieldValue(name)
})
changeStatus({ ...query, query_param: handelTagParam(params) }, callback)
},
[changeStatus, handelTagParam, tagGroupNames]
)
const handelDownload = throttle(
() => {
const fieldsValue = tableFormRef?.current?.getFieldsValue()
const param = {
data_type: 1,
// 所有内容都处理成字符串
query_param: JSON.stringify(
qs.parse(
qs.stringify(
handleParam({
...fieldsValue,
...caculateDate(
fieldsValue.commission_group_date,
'commission_group_date',
fieldsValue
)
})
)
)
)
}
downloadCommissionList(param)
},
3000,
{ trailing: false }
)
// 是否展示不结算原因
const showReason = [
COMMISSION_TAB_MAP.CHECKOUT,
COMMISSION_TAB_MAP.HISTORY
].includes(activeTabKey)
// 是否展示操作
const showOperation = [
COMMISSION_TAB_MAP.CHECK,
COMMISSION_TAB_MAP.CHECKOUT
].includes(activeTabKey)
// 是否展示结算时间选择 [当期结算,下期结算]
const showSelection = [
COMMISSION_TAB_MAP.CHECK,
COMMISSION_TAB_MAP.CHECKOUT
].includes(activeTabKey)
// 是否展示 「操作状态列」
const showOperationStatus = [
COMMISSION_TAB_MAP.CHECK,
COMMISSION_TAB_MAP.CHECKOUT
].includes(activeTabKey)
// 固定展示列
/**
* 「未结算-待审核」固定:分佣信息、操作状态、操作
* 「未结算」固定:分佣信息、分佣状态、操作状态、操作
* 历史结算」固定:分佣信息、分佣状态
*/
const columns = [
...getColumns({ teamList, showOperationStatus }),
...getTagColumns(tableFormRef),
{
title: '结算时间',
colSize: 4,
dataIndex: 'commission_group_date',
hideInTable: true,
renderFormItem: ({ ...props }) => (
),
search: {
transform: caculateDate
}
},
showReason && {
title: '不结算原因',
dataIndex: 'commission_group_info',
hideInSearch: true,
render: (value) => value?.no_settle_reason || '-'
},
showOperation && {
title: '操作',
dataIndex: 'commission_group_info.commission_group_id',
hideInSearch: true,
width: 100,
render(id, record) {
const { commission_group_info: info } = record
const isPending = get(info, 'op_status') === PENDING_STTAUS
const commisonStatus = get(info, 'commission_group_status')
const ops = CommissionTableConfig[activeTabKey]?.operations || []
const operations =
typeof ops === 'function' ? ops({ status: commisonStatus }) : ops
return (
{operations.map((item) => {
if (item.perms && !CheckPerm(item.perms)) return null
return (
item.onClick(record, {
op: changeStatusWithTag,
cb: reloadTable
})
}
>
{typeof item.title === 'function'
? item.title(record)
: item.title}
)
})}
)
}
}
]
.filter(Boolean)
.map((v) => ({
...v,
fixed:
CommissionTableConfig[activeTabKey].fixedConfig?.includes(v.title) &&
'right'
}))
const toolBarRender = useCallback(() => {
return CommissionTableConfig[activeTabKey].toolBarRender?.map((item) =>
item.perms && !CheckPerm(item.perms) ? null : (
item.onClick(selectedRowKeys, {
op: changeStatusWithTag,
cb: reloadTable
})
}
>
{item.title}
)
)
}, [activeTabKey, selectedRowKeys, changeStatusWithTag, reloadTable])
useEffect(() => {
getTeamList().then((data) => {
setTeamList(data)
})
}, [getTeamList])
const onTabsChange = useCallback(
(activeKey) => {
globalIndex1++
setActiveTabKey(activeKey)
reloadTable()
},
[reloadTable]
)
return (
get(record, 'commission_group_info.commission_group_id')
}
loading={isLoadingCommisionList}
search={{
span: 8,
labelWidth: 150,
defaultCollapsed: false,
collapseRender: () => null,
optionRender: (searchConfig, formProps, dom) => [
...dom,
导出
]
}}
scroll={{ x: 'max-content' }}
rowSelection={{
selectedRowKeys,
onChange: (keys) => setSelectedRowKeys(keys),
getCheckboxProps: (record) => {
return {
disabled:
get(record, 'commission_group_info.op_status') === PENDING_STTAUS // Column configuration not to be checked
}
}
}}
debounceTime={500}
formRef={tableFormRef}
form={{
labelAlign: 'right'
}}
toolbar={{
menu: {
type: 'tab',
activeKey: activeTabKey,
items: COMMISSION_TAB,
onChange: onTabsChange
}
}}
toolBarRender={toolBarRender}
options={false}
columns={columns}
request={async (params) => {
const curIndex = globalIndex1
const {
success,
data: { items = [], pagination: { total = 0 } = {} } = {}
} = await loadCommissionList(handleParam(params))
if (curIndex === globalIndex1) {
//快速切换tab导致数据错乱,通过变量控制是否设置返回数据
tableListRef.current = {
items,
total
}
}
return {
data: success ? tableListRef.current.items : [],
success: true,
total: success ? tableListRef.current.total : 0
}
}}
/>
)
}
CommisionList.propTypes = {
isLoadingCommisionList: PropTypes.bool,
loadCommissionList: PropTypes.func,
getTeamList: PropTypes.func,
downloadCommissionList: PropTypes.func,
getCommisionTags: PropTypes.func,
changeStatus: PropTypes.func
}
export default compose(commission, common, withUrlQuery)(CommisionList)
`
### © 版本信息
- ProComponents 版本: [e.g. 4.21.1]
- umi 版本
- 浏览器环境
- 开发环境 [e.g. mac OS]
### 🚑 其他信息
Contributor guide
Research direction
Start with the ProTable request callback, formRef.submit(), and toolbar menu onChange paths shown in the reproduction. Reproduce rapid tab switches and inspect request completion ordering; done means every submit issues a request and the displayed data matches the active tab.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- react, typescript
- Domain
- frontend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100