今天遇到这样一个需求:
一个很简单的左右布局。要实现点击左侧数据更新右侧表格。这个表格因为在多处用到,所以被单独封装。表格勾选和全选的逻辑写在了表格这个组件内部。而这也导致了一个问题:每次点击左侧的数据,右侧的表格并没有重置状态。那如何解决这个问题?
表格的全选和勾选与全选的状态关联是根据selectRowKeys来控制的。如果selectRowKeys=[],那表格每行的勾选状态将被清空。所以关键就是要在每次点击左侧树形菜单的时候进selectRowKeys的操作。
第一种方法:既然表格的状态被单独封装到了表格的组件里。那我再点击父组件左侧的树形菜单时,直接操作表格组件本身,然后通过组件本身的方法去做操作不就可以了吗?沿着这个思路。
我们引出来reactHooks里几个钩子:
useImperativeHandle
useRef
forwardRef
具体使用如下:
(1)父组件使用?useRef ?创建一个?ref ?传入 子组件
const childrenRef = useRef(null);
return <children ref={childrenRef} />
(2)子组件使用?useImperativeHandle ?暴露?ref ?自定义的实例值给父组件。这个需要用?forwardRef ?包裹
function children(props, ref) {
useImperativeHandle(ref, () => ({
hello: () => console.log('hello world!')
}))
return <h1>children</h1>
}
export default forwardRef(children);
最后在父组件中调用
const childrenRef = useRef(null);
const something = () => childrenRef.current.hello();
还是回到我们的表格这个案例。我们看看封装的table这个组件
import { useState, useEffect, useImperativeHandle, forwardRef } from "react"
import {
Table,
Row,
Col,
Checkbox
} from "antd"
import "./index.less"
function QuotaTable(props, ref) {
console.log("表格props:", props)
let { columns,
dataSource,
total,
resetTable,
queryQuotaByPage,
renderTitleRtConts = <span></span>
} = props
// renderTitleRtConts 头部右侧操作内容
const [selectedRowKeys, setSelectedRowKeys] = useState([])
const [isCheckeAll, setIsCheckeAll] = useState(false)
const reset = () => {
setSelectedRowKeys([])
setIsCheckeAll(false)
}
const selectAll = (e) => {
let keys = []
if (e.target.checked) {
keys = dataSource.map(i => i.key)
} else {
keys = []
}
console.log("keys:", keys)
setSelectedRowKeys(keys)
setIsCheckeAll(e.target.checked)
props.getSelectedTableIds(keys)
}
const changePage = (cur) => {
console.log("cur:", cur)
queryQuotaByPage(cur)
}
const rowSelection = {
onChange: (selectedRowKeys, selectedRows) => {
if (selectedRowKeys.length === dataSource.length) {
setSelectedRowKeys(selectedRowKeys)
setIsCheckeAll(true)
} else {
setSelectedRowKeys(selectedRowKeys)
setIsCheckeAll(false)
}
props.getSelectedTableIds(selectedRowKeys)
},
selectedRowKeys,
getCheckboxProps: (record) => ({
disabled: record.name === 'Disabled User',
name: record.name,
}),
};
useImperativeHandle(ref,
() => ({
selectAll,
reset,
rowSelection
}))
//分液器设置
const paginationProps = {
showSizeChanger: true,//设置每页显示数据条数
showQuickJumper: false,
showTotal: () => `共${total}条`,
pageSize: 20,
total, //数据的总的条数
onChange: (current) => changePage(current), //点击当前页码
}
return (
<div className="quota-container">
<Table
size="small"
loading={props.loading}
title={(data) =>
<div className="table-title">
<Row>
<Col span={12}>
<Checkbox
onChange={(e) => selectAll(e)}
checked={isCheckeAll}>全选</Checkbox>
已选<span className="num">{selectedRowKeys.length}</span>个对象,共1200个对象
</Col>
<Col span={12} >
<div className="table-title-rt">{renderTitleRtConts}</div>
</Col>
</Row>
</div>
}
resetTable={resetTable}
hideSelectAll={true}
rowSelection={rowSelection}
columns={columns}
dataSource={dataSource}
pagination={paginationProps}
>
</Table>
</div>
)
}
export default forwardRef(QuotaTable)
注意:我们把要暴露出去的方法通过useImperativeHandle进行包装,通过把QuotaTable这个组件通过forwardRef进行包裹。这里我们其实只需要暴露reset这个方法即可。
最后我们在父组件中调用:
const selectTree = (selectedKeys, { node }) => {
let item = deepCopy(node)
let params = {}
if (node.code) { //点击其他层级
params = { ...quotaParams, categoryId: node.id, shopCode: activeKey, setMealCode: node.code }
} else {
params = { ...quotaParams, setMealCode: node.id, shopCode: activeKey }
}
console.log("params", params)
setCurTreeItem(item)
setQuotaParams(params)
queryQuota(params)
//重置表格勾选状态
tableRef.current.reset()
}
return (
<div>
{
treeData.length == 0 ? <Empty /> : <Tree
defaultExpandParent
onSelect={selectTree}
treeData={treeData}
titleRender={renderTitle}
/>
}
<QuotaTable
ref={tableRef}
columns={columns}
loading={tableLoading}
dataSource={tableList}
total={total}
queryQuotaByPage={queryQuotaByPage}
getSelectedTableIds={getSelectedTableIds}
renderTitleRtConts={
<Space >
<Button
type="primary"
disabled={disabledAddBtn()}
onClick={addQuota}
>
添加定额
</Button>
<Button
type="primary"
disabled={tableSelectedIds.length > 0 ? false : true}
onClick={copyQuota}
>
复制
</Button>
<Button
type="primary"
disabled={tableSelectedIds.length > 0 ? false : true}
onClick={remove}
>
移除
</Button>
<Popover
showCancel={false}
title={FilteredForm}
trigger="click"
>
<Iconfont
type="icon-guolv"
className="filter" />
</Popover>
</Space>
}>
</QuotaTable>
)
</div>
tableRef.current获取到子组件的实例以后直接调用reset方法就可以解决这个问题
|