从子组件调用父组件中的回调时,reactjs-State变量为空

mnowg1ta  于 2022-09-21  发布在  React
关注(0)|答案(1)|浏览(247)

**编辑:**我找到了解决方案,这是由于克布雷泽的建议,以及对桌钩如何工作的更多了解(我在YouTube上找到了这些,愚蠢地没有完全理解)。通过道具回调将currentData发送回ParentComponent是我从他们的回答中得到的。但是,从tableHooks向回调传递currentData不起作用。然后我意识到,虽然它能够访问行,但它不能访问CurrentData。将Cell: ({ row })更改为Cell: ({ currentData, row })成功了。

如果你正试图在自己的Reaction应用程序中解决类似的问题,这可能不是确切的答案,但我建议你理解克莱泽的答案,希望这能让你踏上前进的道路。

原问题:

几天来,我一直遇到一个问题,似乎是因为我缺乏使用Reaction和Java脚本的经验,但由于不知道问题是什么,所以很难找到解决方案。以下是一些示例代码,在某种程度上隔离了这个问题:

export const ParentComponent = () => {
    const [currentData, setCurrentData] = useState([]);

    const fetchCurrentData = async () => {
        let fetchedCurrentData = await getFunctions.getCurrentData();
        setCurrentData(fetchedCurrentData);
    }

    const handleButtonPress = (row) => {
        console.log(currentData);
    }

    return (
        <div>
            <ChildComponent data={currentData} handleButtonPress={handleButtonPress} />
        </div>
    )
}

export default function ChildComponent(props) => {
    const columns = useMemo(() => COLUMNS, []);
    const data = useMemo(() => props.data, [props.data]);

    const tableHooks = (hooks) => {
        hooks.visibleColumns.push((columns) => [
            ...columns, {
                id: "add",
                Header: "Add",
                Cell: ({ row }) => (
                    <button onClick={() => props.handleButtonPress()}>Add</button>
                )
            }
        ])
    }

    const {
        getTableProps,
        getTableBodyProps,
        headerGroups,
        rows,
        prepareRow
    } = useTable({
        columns,
        data
    }, tableHooks);

    return (
        <div>
            <table {...getTableProps()}>
                <thead>
                    {headerGroups.map(headerGroup => (
                        <tr {...headerGroup.getHeaderGroupProps()}>
                            {
                                headerGroup.headers.map(column => (
                                    <th {...column.getHeaderProps()}>{column.render('Header')}</th>
                                ))
                            }
                        </tr>
                    ))}
                </thead>
                <tbody {...getTableBodyProps()}>
                    {rows.map((row, i) => {
                        prepareRow(row);
                        return (
                            <tr {...row.getRowProps()}>
                                {
                                    row.cells.map(cell => {
                                        return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>;
                                    })
                                }
                            </tr>
                        );
                    })}
                </tbody>
            </table>
        </div>
    )
}

流程是这样的:

1.接收数据
1.使用setCurrentData更新currentData状态变量
1.重新渲染ParentComponent
1.ChildComponent也被渲染,并通过道具接收currentData
1.此外,ChildComponent通过道具接收函数handleButtonPress
1.ChildComponent使用react-table(v7.8.0)显示数据,然后通过挂钩在表中创建额外的列,每一行都有一个按钮
1.按钮设置为从道具onClick调用handleButtonPress
1.按下按钮,调用handleButtonPress

上述流程运行正常。当从ChildComponent调用函数handleButtonPress时,当console.log(currentData)记录一个空数组而不是currentData的实际状态时,就会出现该问题。在重新渲染ParentComponent之前,我已验证currentData已填充,并且它已成功到达ChildComponent

将非常感谢在这方面的一些帮助!如果我必须猜测哪里出错了,那就是通过道具传递函数handleButtonPress可能会在设置currentData之前发送该函数的一个版本,但就像我说的那样,我对Reaction非常缺乏经验,这只是一个猜测!

谢谢你的阅读。

h5qlskok

h5qlskok1#

有两条缺失的信息使你无法100%肯定地回答你的问题:

1.如何调用fetchCurrentData
1.如何使用和调用tableHooks

然而,即使没有这些信息,我也可以很好地告诉您问题是什么。

首先要了解的是,每次重新呈现ParentComponent时,您都在定义一个全新的handleButtonPress函数。

第二件要理解的事情是,在fetchCurrentData函数中调用setCurrentData之后,ParentComponent中的currentData变量会更改Identity。这意味着,与第一次相比,第二次重新渲染ParentComponent时,它实际上是一个完全不同的变量。

第三件要理解的事情是,handleButtonPress函数在currentData变量周围形成一个闭包。但是,由于currentData的身份在两次重新呈现之间会发生变化,因此要关闭的变量实际上是不同的。换句话说,第一次重新呈现的handleButtonPress函数关闭了第一次重新呈现的currentData变量,该变量被固定为[]。第二次重新渲染的handleButtonPress函数关闭了第二次重新渲染的currentData变量,该变量包含您的实际数据。

最后,我怀疑tableHooks在第一次呈现ChildComponent期间只被调用一次props.handleButtonPress函数是第一个handleButtonPress函数,它与第一个currentData函数[]一起使用。

解决办法?

在调用handleButtonPress函数时,将相关数据传递给该函数。即,将函数签名更改为:

const handleButtonPress = (row, data) => {
        console.log(data);
    }

顺便说一句,现在该函数是一个“纯”函数--它没有副作用(除了登录到控制台之外),它完全依赖于它的输入。您可以将要定义的函数移到呈现循环之外以获得(非常小的)性能改进,这也是声明“这确实是一个纯函数”的一种非常有用的方式。

一般来说,更喜欢纯函数,避免依赖副作用,以避免遇到像您在这里遇到的棘手情况。

相关问题