1、背景
在React使用antd Table组件需要多选的时候都会出现一个问题,使用onChange事件的前两个参数来获取选中的数据。就是本来选中了第一页的数据,再切换到第二页选择时,第一页选中的数据就没了,相信大家会经常遇到这个问题。
2、问题原因
这个问题的原因是因为我们正常列表都是分页请求数据,在切换到第二页时,其实第一页的数据就已经没有了,会重新请求第二页的数据;当点击选中时就只有第二页数据了,所以选中的也只会是当前页的数据,其他页的就丢了。
3、问题解决
那要如何解决这个问题呢?要解决这个问题就只能利用table组件所提供的另外两个事件了,onSelect和onSelectAll,用onSelect这个来实现单行的选中和取消选中,onSelectAll实现整页的选中和取消选中。
4、具体代码实现
封装了一个hooks,key默认为id
import { useState } from 'react'
// import { unique } from '@/utils'
// 对象数组去重
export const unique = (list = [], key = 'id') => {
return [...list.reduce((map, item) => {
if (!map.has(item[key])) map.set(item[key], item)
return map
}, new Map()).values()]
}
export default function useTableSelected(key = 'id') {
const [selectedRowKeys, setSelectedRowKeys] = useState([])
const [selectedRows, setSelectedRows] = useState([])
// 选中的行 去空,去重
const selectedRowsUnique = (list = []) => {
const rows = list.filter(Boolean)
return unique([...selectedRows, ...rows])
}
// 点击取消/选中 单行 用户手动选择/取消选择某行的回调
const onSelectRow = (record, selected, selectedRows) => {
const newRows = selectedRowsUnique(selectedRows)
const arr = newRows.filter(item => {
if (item[key] === record[key]) {
return selected
}
return true
})
setSelectedRows(arr)
setSelectedRowKeys(arr.map(item => item[key]))
}
// 点击取消/选中 一页的所有 用户手动选择/取消选择所有行的回调
const onSelectAllRow = (selected, selectedRows, changeRows) => {
let newRows = selectedRowsUnique(selectedRows)
if (!selected) {
const arr = changeRows.map(item => item[key])
newRows = newRows.filter(item => !arr.includes(item[key]))
}
setSelectedRows(newRows)
setSelectedRowKeys(newRows.map(item => item[key]))
}
// 选中项发生变化时的回调
const onChange = (selectedRowKeys, selectedRows, info) => {
// 点击别的取消选中时清空所有
if (info.type === 'none') {
setSelectedRowKeys([])
setSelectedRows([])
}
}
return {
onChange,
onSelect: onSelectRow,
onSelectAll: onSelectAllRow,
selectedRowKeys,
selectedRows
}
}
5、效果
第一页选中了9个
第二页选上不会丢