react hook useState trong hàm AgGridColumn onCellClicked

Sep 12 2020

Hiện tại, tôi đang sử dụng các thành phần phản ứng chức năng với móc phản ứng useStatevà một AgGridReactThành phần.

Tôi đang hiển thị một AgGridReactvà đặt một onCellClickedhàm trên a AgGridColumn. Cho đến nay mọi thứ đang hoạt động. Trong onCellClickedhàm, tôi muốn cập nhật trạng thái của mình và thực hiện điều gì đó tùy thuộc vào giá trị hiện tại của nó.

Đây là vấn đề:

nếu tôi muốn sử dụng trạng thái get / set ( useStatehook) bên trong của onCellClickedhàm, nó không hoạt động như mong đợi. Vì một số lý do, tôi không thể cập nhật trạng thái của mình.

Trong một thành phần lớp phản ứng, nó đang hoạt động.

CHỈNH SỬA: Tôi đã thử nghiệm một thời gian và phát hiện ra rằng trong onCellClickedhàm tôi chỉ có giá trị mặc định trong myText. Tôi có thể cập nhật nó một lần. Nếu tôi spam, onCellClickedchức năng này sẽ nối văn bản lại với giá trị mặc định từ đó useState("default myText");. Tôi hy vọng rằng chuỗi sẽ dài hơn thường xuyên khi tôi nhấp vào ô. Cũng giống như trong ví dụ Thành phần lớp của tôi. Nếu tôi sử dụng một nút đơn giản bên ngoài, AgGridReact <button onClick={() => setMyText(myText + ", test ")}>add something to myText state</button>nó đang hoạt động như mong đợi, chuỗi sẽ dài hơn mỗi khi tôi nhấp vào của tôi <button>. Nếu tôi thay đổi trạng thái của myText thông qua <button>bên ngoài AgGridReactvà sau đó nhấp vào chức năng ô một lần nữa, trạng thái được thiết lập trước đó thông qua của tôi <button>sẽ bị mất.

Ví dụ về thành phần 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;

Nếu tôi làm điều tương tự trong một thành phần lớp thì nó vẫn hoạt động tốt.

Thành phần lớp mẫu:

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;

Tôi có làm điều gì sai? Tôi muốn sử dụng một thành phần chức năng với các móc phản ứng.

Trả lời

1 NearHuscarl Sep 12 2020 at 14:36

Không có gì sai với mã trong câu hỏi của bạn ngoại trừ việc gọi lại myCellClickFunctiontham chiếu đến trạng thái cũ myTextđược ghi lại trong lần gọi hiển thị trước đó. Nếu bạn đăng nhập vào phương thức kết xuất, bạn có thể thấy trạng thái được cập nhật đúng cách. Vấn đề này được gọi là đóng cửa cũ .

function App() {
  const [myText, setMyText] = useState("default myText");
  const [todoListRowData, setTodoListRowData] = useState(rowData);

  console.log("render", myText); // prints the latest myText state
  ...
}

Bạn có thể xem câu trả lời khác của tôi ở đây về cách lấy trạng thái mới nhất trong lệnh gọi lại khi sử dụng React hook. Đây là một ví dụ để bạn thử điều đó.

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);
  };
  ...
}

Bản thử trực tiếp