在 AgGridColumn onCellClicked 函数中反应挂钩 useState
react hook useState in AgGridColumn onCellClicked function
目前,我正在使用带有反应挂钩 useState
和 AgGridReact
组件的功能性反应组件。
我正在显示一个 AgGridReact
并在 AgGridColumn
上放置一个 onCellClicked
函数。到目前为止一切正常。在 onCellClicked
函数中,我想更新我的状态并根据其当前值做一些事情。
问题是:
如果我想在 onCellClicked
函数中使用我的状态 get/set(useState
钩子),它无法按预期工作。由于某些原因,我无法更新我的状态。
在 React class 组件中它正在工作。
编辑: 我试验了一段时间,发现在 onCellClicked
函数中我只有 myText 中的默认值。我可以更新一次。如果我向 onCellClicked
函数发送垃圾邮件,它会再次将文本附加到 useState("default myText");
的默认值。我希望字符串会随着我单击单元格的频率而变长。就像我的 Class 组件示例一样。
如果我在 AgGridReact
<button onClick={() => setMyText(myText + ", test ")}>add something to myText state</button>
之外使用一个简单的按钮,它会按预期工作,每次我单击 <button>
时字符串都会变长。如果我通过 AgGridReact
之外的 <button>
更改 myText 的状态,然后再次单击单元格功能,之前通过我的 <button>
设置的状态将丢失。
示例反应挂钩组件:
import React, { useState } from 'react';
import { AgGridColumn, AgGridReact } from 'ag-grid-react';
import 'ag-grid-community/dist/styles/ag-grid.css';
import 'ag-grid-community/dist/styles/ag-theme-alpine.css';
function App() {
const [myText, setMyText] = useState("default myText");
const [todoListRowData, setTodoListRowData] = useState([]);
// ....fetch data and set the todoListRowData state....
const myCellClickFunction = (params, x) => {
// here is the problem:
// no matter how often I click in the cell myText is every time the default value 'default myText'
// EDIT: I found out I can update the state here but only from the initial default value once, myText is on every cell click again "default myText" and will be concatenated with "hookCellClicked". So every time I click this cell the state gets again "default myTexthookCellClicked"
console.log(myText);
setMyText(myText + "hookCellClicked");
}
return (
<div className="ag-theme-alpine" style={{ height: '600px', width: '100%' }}>
<AgGridReact rowData={todoListRowData} >
<AgGridColumn headerName="ID" field="id" maxWidth="50"></AgGridColumn>
<AgGridColumn headerName="UserId" field="userId" maxWidth="85"></AgGridColumn>
<AgGridColumn headerName="Title" field="title" minWidth="555"></AgGridColumn>
<AgGridColumn headerName="completed" field="completed"></AgGridColumn>
<AgGridColumn headerName="Testcol" onCellClicked={(params) => myCellClickFunction(params)}></AgGridColumn>
</AgGridReact>
</div>
}
export default App;
如果我在 class 组件中做完全相同的事情,它工作正常。
示例Class 组件:
import React from 'react';
import { AgGridColumn, AgGridReact } from 'ag-grid-react';
import 'ag-grid-community/dist/styles/ag-grid.css';
import 'ag-grid-community/dist/styles/ag-theme-alpine.css';
class MyClassComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
myClassComponentRowData: [],
testState: "defaul testState"
};
}
// ....fetch data and set ag grid rowData state....
handleCellClick = (params) => {
// here everything works just fine and as expected
// every time I click on the cell the state testState updates and it is added ", handleCellClick" every time
console.log(this.state.testState);
this.setState({testState: this.state.testState + ", handleCellClick"});
}
render() {
return <div className="ag-theme-alpine" style={{ height: '600px', width: '100%' }}>
<AgGridReact rowData={this.state.myClassComponentRowData} >
<AgGridColumn headerName="ID" field="id" maxWidth="50"></AgGridColumn>
<AgGridColumn headerName="UserId" field="userId" maxWidth="85"></AgGridColumn>
<AgGridColumn headerName="Title" field="title" minWidth="555"></AgGridColumn>
<AgGridColumn headerName="completed" field="completed"></AgGridColumn>
<AgGridColumn headerName="Testcol" onCellClicked={(params) => this.handleCellClick(params)}></AgGridColumn>
</AgGridReact>
</div>
}
}
export default MyClassComponent;
我是不是做错了什么?我想使用带有反应钩子的功能组件。
除了回调 myCellClickFunction
引用了在之前的渲染调用中捕获的旧状态 myText
之外,您问题中的代码没有任何问题。如果您登录渲染方法,您可以看到状态已正确更新。这个问题叫做 stale closure.
function App() {
const [myText, setMyText] = useState("default myText");
const [todoListRowData, setTodoListRowData] = useState(rowData);
console.log("render", myText); // prints the latest myText state
...
}
你可以看我的另一个回答关于使用React hook时如何在回调中获取最新状态。这是供您尝试的示例。
function useExtendedState(initialState) {
const [state, setState] = React.useState(initialState);
const getLatestState = () => {
return new Promise((resolve, reject) => {
setState((s) => {
resolve(s);
return s;
});
});
};
return [state, setState, getLatestState];
}
function App() {
const [myText, setMyText, getLatestMyText] = useExtendedState(
"default myText"
);
const myCellClickFunction = async (params) => {
setMyText(params.value);
const text = await getLatestMyText();
console.log("get latest state in callback", text);
};
...
}
现场演示
目前,我正在使用带有反应挂钩 useState
和 AgGridReact
组件的功能性反应组件。
我正在显示一个 AgGridReact
并在 AgGridColumn
上放置一个 onCellClicked
函数。到目前为止一切正常。在 onCellClicked
函数中,我想更新我的状态并根据其当前值做一些事情。
问题是:
如果我想在 onCellClicked
函数中使用我的状态 get/set(useState
钩子),它无法按预期工作。由于某些原因,我无法更新我的状态。
在 React class 组件中它正在工作。
编辑: 我试验了一段时间,发现在 onCellClicked
函数中我只有 myText 中的默认值。我可以更新一次。如果我向 onCellClicked
函数发送垃圾邮件,它会再次将文本附加到 useState("default myText");
的默认值。我希望字符串会随着我单击单元格的频率而变长。就像我的 Class 组件示例一样。
如果我在 AgGridReact
<button onClick={() => setMyText(myText + ", test ")}>add something to myText state</button>
之外使用一个简单的按钮,它会按预期工作,每次我单击 <button>
时字符串都会变长。如果我通过 AgGridReact
之外的 <button>
更改 myText 的状态,然后再次单击单元格功能,之前通过我的 <button>
设置的状态将丢失。
示例反应挂钩组件:
import React, { useState } from 'react';
import { AgGridColumn, AgGridReact } from 'ag-grid-react';
import 'ag-grid-community/dist/styles/ag-grid.css';
import 'ag-grid-community/dist/styles/ag-theme-alpine.css';
function App() {
const [myText, setMyText] = useState("default myText");
const [todoListRowData, setTodoListRowData] = useState([]);
// ....fetch data and set the todoListRowData state....
const myCellClickFunction = (params, x) => {
// here is the problem:
// no matter how often I click in the cell myText is every time the default value 'default myText'
// EDIT: I found out I can update the state here but only from the initial default value once, myText is on every cell click again "default myText" and will be concatenated with "hookCellClicked". So every time I click this cell the state gets again "default myTexthookCellClicked"
console.log(myText);
setMyText(myText + "hookCellClicked");
}
return (
<div className="ag-theme-alpine" style={{ height: '600px', width: '100%' }}>
<AgGridReact rowData={todoListRowData} >
<AgGridColumn headerName="ID" field="id" maxWidth="50"></AgGridColumn>
<AgGridColumn headerName="UserId" field="userId" maxWidth="85"></AgGridColumn>
<AgGridColumn headerName="Title" field="title" minWidth="555"></AgGridColumn>
<AgGridColumn headerName="completed" field="completed"></AgGridColumn>
<AgGridColumn headerName="Testcol" onCellClicked={(params) => myCellClickFunction(params)}></AgGridColumn>
</AgGridReact>
</div>
}
export default App;
如果我在 class 组件中做完全相同的事情,它工作正常。
示例Class 组件:
import React from 'react';
import { AgGridColumn, AgGridReact } from 'ag-grid-react';
import 'ag-grid-community/dist/styles/ag-grid.css';
import 'ag-grid-community/dist/styles/ag-theme-alpine.css';
class MyClassComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
myClassComponentRowData: [],
testState: "defaul testState"
};
}
// ....fetch data and set ag grid rowData state....
handleCellClick = (params) => {
// here everything works just fine and as expected
// every time I click on the cell the state testState updates and it is added ", handleCellClick" every time
console.log(this.state.testState);
this.setState({testState: this.state.testState + ", handleCellClick"});
}
render() {
return <div className="ag-theme-alpine" style={{ height: '600px', width: '100%' }}>
<AgGridReact rowData={this.state.myClassComponentRowData} >
<AgGridColumn headerName="ID" field="id" maxWidth="50"></AgGridColumn>
<AgGridColumn headerName="UserId" field="userId" maxWidth="85"></AgGridColumn>
<AgGridColumn headerName="Title" field="title" minWidth="555"></AgGridColumn>
<AgGridColumn headerName="completed" field="completed"></AgGridColumn>
<AgGridColumn headerName="Testcol" onCellClicked={(params) => this.handleCellClick(params)}></AgGridColumn>
</AgGridReact>
</div>
}
}
export default MyClassComponent;
我是不是做错了什么?我想使用带有反应钩子的功能组件。
除了回调 myCellClickFunction
引用了在之前的渲染调用中捕获的旧状态 myText
之外,您问题中的代码没有任何问题。如果您登录渲染方法,您可以看到状态已正确更新。这个问题叫做 stale closure.
function App() {
const [myText, setMyText] = useState("default myText");
const [todoListRowData, setTodoListRowData] = useState(rowData);
console.log("render", myText); // prints the latest myText state
...
}
你可以看我的另一个回答
function useExtendedState(initialState) {
const [state, setState] = React.useState(initialState);
const getLatestState = () => {
return new Promise((resolve, reject) => {
setState((s) => {
resolve(s);
return s;
});
});
};
return [state, setState, getLatestState];
}
function App() {
const [myText, setMyText, getLatestMyText] = useExtendedState(
"default myText"
);
const myCellClickFunction = async (params) => {
setMyText(params.value);
const text = await getLatestMyText();
console.log("get latest state in callback", text);
};
...
}