在AgGridColumn onCellClicked函数中反应钩子useState

时间:2020-09-12 06:56:22

标签: reactjs react-hooks use-state ag-grid-react

目前,我正在使用带有React钩子useStateAgGridReact组件的功能性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挂钩的功能组件。

1 个答案:

答案 0 :(得分:1)

您的问题中的代码没有任何问题,只是回调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);
  };
  ...
}

实时演示

Edit AgGrid Get Latest State In Callback