问题描述
目前,我正在使用带有React钩子useState
和AgGridReact
组件的功能性React组件。
我正在显示AgGridReact
,并将onCellClicked
函数放在AgGridColumn
上。到目前为止,一切正常。在onCellClicked
函数中,我想更新状态并根据其当前值执行某些操作。
这是问题所在:
如果我想在useState
函数中使用状态获取/设置(onCellClicked
钩子),则无法正常工作。由于某些原因,我无法更新状态。
它在React类组件中正常工作。
编辑:我做了一段时间的实验,发现在onCellClicked
函数中,myText中只有默认值。我可以更新一次。如果我向onCellClicked
函数发送了垃圾邮件,它将再次将文本附加到useState("default myText");
的默认值之后。我希望当我单击单元格时,字符串会变得更长。就像在我的类组件示例中一样。
如果我在AgGridReact
<button onClick={() => setMyText(myText + ",test ")}>add something to myText state</button>
外面使用了一个简单的按钮,它可以按预期工作,那么每次我点击<button>
时,字符串就会变长。如果我通过<button>
之外的AgGridReact
更改myText的状态,然后再次单击单元格功能,则先前通过我的<button>
设置的状态将丢失。
示例react hook组件:
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;
如果我在类组件中执行完全相同的操作,则工作正常。
示例类组件:
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;
我做错什么了吗?我想使用带有React挂钩的功能组件。
解决方法
您的问题中的代码没有任何问题,只是回调myCellClickFunction
引用了旧状态myText
,该状态是在上一个渲染调用中捕获的。如果登录render方法,则可以看到状态已正确更新。这个问题称为过期封包。
function App() {
const [myText,setMyText] = useState("default myText");
const [todoListRowData,setTodoListRowData] = useState(rowData);
console.log("render",myText); // prints the latest myText state
...
}
您可以看到我的其他答案here,有关使用React钩子时如何在回调中获取最新状态。这是供您尝试的示例。
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);
};
...
}