TypeError: Cannot read properties of undefined (reading 'forEach') when trying to combine react-table with react-query

TypeError: Cannot read properties of undefined (reading 'forEach') when trying to combine react-table with react-query

我正在尝试将 react-table 与 react-query 结合起来以获得动态的 editable table ,它最初由数据库中的数据填充。

import React from 'react';
import Style from './CLGridStyle.js';
import axios from 'axios';
import { useTable, useBlockLayout, useResizeColumns } from 'react-table';
import { useQuery, QueryClient, QueryClientProvider, useQueryClient } from 'react-query'

const EditableCell = ({
  value: initialValue,
  row: { index },
  column: { id, type, readonly },
  updateMyData,
}) => {
  // We need to keep and update the state of the cell normally
  const [value, setValue] = React.useState(initialValue)

  const onChange = e => {
    setValue(e.target.value)
  }

  const onCheckboxChange = e => {
    setValue(e.target.checked);
  }

  // We'll only update the external data when the input is blurred
  const onBlur = () => {
    updateMyData(type, index, id, value);
  }

  // If the initialValue is changed external, sync it up with our state
  React.useEffect(() => {
    setValue(initialValue)
  }, [initialValue])

  switch (type) {
    case 'checkbox':
      return (<input onChange={onCheckboxChange} onBlur={onBlur} type={type} readOnly={readonly}
                    autoComplete="off" checked={value || false} />);
    case 'date':
      return (<input onChange={onChange} onBlur={onBlur} type={type} readOnly={readonly}
                    autoComplete="off" value={(value || "").slice(0, 10)} />);
    default:
      return (<input onChange={onChange} onBlur={onBlur} type={type} readOnly={readonly}
                    autoComplete="off" value={value || ""} />);
  }
}

function CLGrid({ columns }) {
  const queryClient = useQueryClient();

  const [data, setData] = React.useState([]);

  const { apiResponse, isLoading } = useQuery('users', () => axios.get(`http://www.test.devel/users`));

  React.useEffect(() => {
    setData(apiResponse?.data);
  }, [apiResponse]);

  const updateMyData = (type, rowIndex, columnId, value) => {
    setData(old =>
      old.map((row, index) => {
        if (index === rowIndex) {
          return {
            ...old[rowIndex],
            [columnId]: value,
          }
        }
        return row
      })
    )
  }

  const defaultColumn = React.useMemo(
    () => ({
      minWidth: 30,
      width: 150,
      maxWidth: 400,
      Cell: EditableCell,
    }),
    []
  );

  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    prepareRow,
    state,
  } = useTable(
    {
      columns, data, defaultColumn, updateMyData
    },
    useBlockLayout,
    useResizeColumns
  );

  React.useEffect(() => {
    if (state.columnResizing.isResizingColumn === null) {
      console.log('columnResizing', state.columnResizing);
    }
  }, [state.columnResizing]);

  if (isLoading || !data) {
    return (<div>Loading...</div>);
  }

  return (
    <Style>
      <div {...getTableProps()} className="table">
        <div>
          {headerGroups.map(headerGroup => (
            <div {...headerGroup.getHeaderGroupProps()} className="tr">
              {headerGroup.headers.map(column => (
                <div {...column.getHeaderProps()} className="th">
                  {column.render('Header')}
                  <div {...column.getResizerProps()} className="resizer" />
                </div>
              ))}
            </div>
          ))}
        </div>
        <div {...getTableBodyProps()}>
          {rows.map((row, i) => {
            prepareRow(row)
            return (
              <div {...row.getRowProps()} className="tr">
                {row.cells.map(cell => {
                  return (
                    <div {...cell.getCellProps()} className="td">
                      {cell.render('Cell')}
                    </div>
                  )
                })}
              </div>
            )
          })}
        </div>
      </div>
      <pre>
        <code>{JSON.stringify(state, null, 2)}</code>
      </pre>
      <pre>
        <code>{JSON.stringify(data, null, 2)}</code>
      </pre>
    </Style>
  )
}

const client = new QueryClient();

const ReactQueryWithTable = ({columns}) => {
  return (
    <QueryClientProvider client={client}>
      <CLGrid columns={columns} />
    </QueryClientProvider>
  );
}

export default ReactQueryWithTable;

当我尝试 运行 这个时,我得到这个错误:

TypeError: Cannot read properties of undefined (reading 'forEach')

发生在 useTable 挂钩中的这个位置:

> 591 |   data.forEach((originalRow, rowIndex) =>
  592 |     accessRow(originalRow, rowIndex, 0, undefined, rows)
  593 |   )

到目前为止,我已经花了几个小时对此进行调整,但无济于事。我错过了什么?

useQuery 没有名为 apiResponse 的 属性,因此这可能不起作用:

const { apiResponse, isLoading } = useQuery(...)

useQuery returns 一个名为 data 的字段,您的 api 请求的响应将在其中可用。