React子组件回调父组件状态数据问题?

子组件如下:

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的,无论怎么操作都是正常的。
请问下这是什么原因啊?

阅读 1.7k
1 个回答

组件内部的任何函数,包括事件处理函数和 Effect,都是从它被创建的那次渲染中被「看到」的,所以引用的值任然是旧的。
所以无论是

onOk={() => onOk()}  还是  options={[ ..., { ..., onOk: () => onOk() }  ]}

结果都是

onOk={() => [] }    options={[ ..., { ..., onOk: () => [] }  ]}

你说的 注释// 2 位置的函数 是因为每次修改父组件的值都会刷新当前组件及其子组件

onOk={() => [1] }   也更新为  onOk={() => [2] }  了

options 里的方法表现 ' 异常 ' 是因为useState对其进行了缓存

selectedOption 仍然是初次创建结果 { ..., onOk: () => [] }
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题