我正在使用 React 和 Material UI 创建一个带有一些按钮的表格 (XGrid)。当您单击该行时,它应该使用 useState
设置行 ID。当您单击删除按钮时,它应该删除该行。似乎删除点击处理程序没有使用来自使用状态的值。这要么是某种封闭的东西,要么是某种 React 的东西。
const MyTableThing: React.FC = (props) =>
{
const { data } = props;
const [filename, setFilename] = React.useState<string>("")
const [columns, setColumns] = React.useState<GridColDef[]>([])
const handleDelete = () =>
{
someFunctionThatDeletes(filename); // filename is always ""
setFilename(""); // Does not do anything.. !
}
React.useEffect(() =>
{
if (data)
{
let columns: GridColumns = data.columns;
columns.forEach((column: GridColDef) =>
{
if (column.field === "delete")
{
column.renderCell = (cellParams: GridCellParams) =>
{
return <Button onClick={handleDelete}>Delete</Button>
}
}
})
setColumns(columns)
}
}, [data?.files])
// Called when a row is clicked
const handleRowSelected = (param: GridRowSelectedParams) =>
{
console.log(`set selected row to ${param.data.id}`) // This works every time
setFilename(param.data.id)
}
}
答案 0 :(得分:0)
这种行为的原因是 React 没有同步处理 setState 动作。它与其他状态更改堆叠在一起,然后执行。 React 这样做是为了提高应用程序的性能。阅读以下链接了解更多详情。 https://linguinecode.com/post/why-react-setstate-usestate-does-not-update-immediately
您可以禁用 deleteRow 按钮,直到文件名变量更新。您可以使用带有回调函数的 useEffect 或 setState。
useEffect(() => {
//Enable your delete row button, fired when filename is updated
}, filename)
或
this.setFilename(newFilename, () => {
// ... enable delete button
});
让我知道这是否有帮助!如果有帮助,请将其标记为答案。
答案 1 :(得分:0)
我在这里看到的主要问题是您在 useEffect 钩子中渲染 JSX,然后将输出 JSX 保存到列状态。我假设你然后从这个功能组件返回那个状态 JSX。这是一种非常奇怪的做事方式,我不建议这样做。
然而,这说明了问题。保存在 state 中的 JSX 具有 handleDelete
函数的旧版本,因此当调用 handleDelete
时,它没有 filename
的当前值。
不要使用 useEffect 钩子和列状态,只需在 return 语句中执行此操作即可。或者将工作分配给一个变量,然后渲染该变量。或者更好的是,使用 useMemo 钩子。
请注意,我们将 handleDelete 添加到 useMemo 依赖项中。这样,它会在每次 handleDelete 更改时重新渲染。目前每次渲染都会改变。所以让我们通过将 useCallback 添加到 handleDelete 来解决这个问题。
const MyTableThing: React.FC = (props) => {
const { data } = props;
const [filename, setFilename] = React.useState<string>('');
const handleDelete = React.useCallback(() => {
someFunctionThatDeletes(filename); // filename is always ""
setFilename(''); // Does not do anything.. !
}, [filename]);
const columns = React.useMemo(() => {
if (!data) {
return null;
}
let columns: GridColumns = data.columns;
columns.forEach((column: GridColDef) => {
if (column.field === 'delete') {
column.renderCell = (cellParams: GridCellParams) => {
return <Button onClick={handleDelete}>Delete</Button>;
};
}
});
return columns;
}, [data?.files, handleDelete]);
// Called when a row is clicked
const handleRowSelected = (param: GridRowSelectedParams) => {
console.log(`set selected row to ${param.data.id}`); // This works every time
setFilename(param.data.id);
};
return columns;
};