子组件如下:
import { Button, Select } from "antd"; import { useState } from "react"; const BatchOperation = (props: BatchOperationProps) => { const { options = [], onOk: globalOk, onChange } = props; const [selectedOption, setSelectedOption] = useState<OperationType>(options[0]); const { onOk = globalOk } = selectedOption; return <div style={{ padding: 6, border: '1px solid #d8d8d8', display: 'inline-flex', gap: 6 }}> <div> <Select options={options} defaultValue={selectedOption?.value} dropdownMatchSelectWidth={false} showSearch={false} style={{ width: 'max-content', maxWidth: 160 }} onChange={selValue => { const selected = options.find(({ value }) => value === selValue); if (!!selected) { setSelectedOption(selected); onChange?.(selValue); } else { throw '选项错误'; } }}></Select> </div> <Button type="primary" onClick={() => { onOk?.(); }}>Button</Button> </div>; }; export default BatchOperation; export interface OperationType { value: string; label: string; onOk?: () => Promise<void>; } interface BatchOperationProps { options: OperationType[] onOk?: () => Promise<void> onChange?: (value: string) => void }
父组件如下:
import { ProColumns, ProTable } from '@ant-design/pro-components'; import { useState } from 'react'; import BatchOperation from './Batch'; import './index.css'; const Test = () => { const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]); const columns: ProColumns<any>[] = [ { title: '员工姓名', dataIndex: 'name' }, { title: '员工工号', dataIndex: 'code' } ]; const onOk = async () => { console.info('ok: ', selectedRowKeys); // 3 }; return ( <ProTable bordered rowKey="code" search={false} options={false} columns={columns} dataSource={dataSource} rowSelection={{ selectedRowKeys, onChange: (keys, rows) => { console.info('selected keys ', keys); setSelectedRowKeys(keys); } }} toolbar={{ menu: { items: [{ key: 'batch', label: <BatchOperation onChange={() => { console.info('change...'); setSelectedRowKeys([]); }} // onOk={() => onOk()} // 2 options={[ { value: 'A', label: '选项一' }, { value: 'B', label: '选项二', onOk: () => onOk() } // 1 ]} /> }] } }} /> ) }; export default Test; const dataSource = [ { name: '张三', code: 'A1' }, { name: '李四', code: 'A2' } ];
如下图操作,进入页面直接选选项二,然后任意勾选之后点按钮,ok的输出不对。

但是像下面这样操作,ok的输出是正确的。
但是使用注释// 2 位置的函数,不实用// 1的,无论怎么操作都是正常的。
请问下这是什么原因啊?
组件内部的任何函数,包括事件处理函数和 Effect,都是从它被创建的那次渲染中被「看到」的,所以引用的值任然是旧的。
所以无论是
onOk={() => onOk()} 还是 options={[ ..., { ..., onOk: () => onOk() } ]}
结果都是
onOk={() => [] } options={[ ..., { ..., onOk: () => [] } ]}
你说的 注释// 2 位置的函数 是因为每次修改父组件的值都会刷新当前组件及其子组件
onOk={() => [1] } 也更新为 onOk={() => [2] } 了
options 里的方法表现 ‘ 异常 ‘ 是因为useState对其进行了缓存
selectedOption 仍然是初次创建结果 { ..., onOk: () => [] }
//const [selectedOption, setSelectedOption] = useState<OperationType>(options[0]);
const [selectedValue, setSelectedValue] = useState<T>(options[0]?.value);
//const { onOk = globalOk } = selectedOption;
const { onOk = globalOk } = options.find(({ value }) => value === selectedValue) || {};
我前面尝试改了下,不再直接存option完整的信息,而是只存value,然后需要的时候去options里去查找出来使用,使用这种方式,就都正常了。虽说改了效果是对了,但是不理解具体原因,看了你的回答后大体上是理解了一些了,就是对象被缓存了。感谢你的回答。