TS с редуцированными фрагментами: valueService.js:205 Неучтенная ошибка типа: Не удается назначить свойство только для чтения » dis «объекта» #»

#javascript #reactjs #typescript #redux

Вопрос:

Я, кажется, не могу понять, что вызывает вышеуказанную проблему, и правильно отлаживаю. Исходя из моего понимания срезов Redux, я могу напрямую изменять состояние в своем редукторе благодаря встроенной функции Immer. Если я жестко закодирую redux JSON в компонент пользовательского интерфейса, то не возникнет никаких проблем, которые заставили бы меня поверить, что это проблема с Redux. Буду признателен за любой совет.

Срез.тс

 
interface LoadSchedulerState {
  gridData: DataRow[] | null,
}
interface DataRow {
  id: number,
  dis: string,
  hour: string
}

const initialState: LoadSchedulerState = {
  gridData: null,
}

export const loadSchedulerSlice = createSlice({
  name: 'load_scheduler',
  initialState,
  reducers: {
    updateGridData: (state, action:  PayloadAction<DataRow>) => {
      let newData = [{...action.payload}]
      return {...state, gridData:newData}
    },
  },
});

export const {updateGridData} = loadSchedulerSlice.actions;
export const gridData = (state: { loadScheduler: { gridData: any; }; }) => state.loadScheduler.gridData;
export default loadSchedulerSlice.reducer;

 

LoadScheduler.ts

 import { AgGridColumn, AgGridReact } from "@ag-grid-community/react";
import HeaderGroupComponent from "./HeaderGroupComponent.jsx";
import LoadHeaderComponent from "./LoadHeaderComponent.jsx";
import BtnCellRenderer from './BtnCellRenderer';
import {
  AllModules,
  ColumnApi,
  GridApi,
  GridReadyEvent,
} from "@ag-grid-enterprise/all-modules";
import "../../styles/DemoGrid.css";
import { updateGridData, gridData } from "./loadSchedulerSlice";
import { useDispatch, useSelector } from 'react-redux';

const LoadSchedulerGrid = () => {
  const [gridApi, setGridApi] = useState<GridApi>();
  const [columnApi, setColumnApi] = useState<ColumnApi>();
  const [rowData, setRowData] = useState<any>(null);
  const gridStateData = useSelector(gridData);
  const dispatch = useDispatch();
  
  // PUSH TABLE CHANGES VIA WEBSOCKET TO BACKEND 
  const handleCellChange = (event: any) => {
    
  }


  var init_data = {   
    id: 0,
    dis: "Mon 10/19 8:09 A",
    hour: "8 a"
  }

  const dataSetter = (params: { newValue: any; data: any; }) => {
    params.data.dis = params.newValue;
    return false;
  };
  
  const onGridReady = (params: GridReadyEvent) => {
    dispatch(updateGridData(init_data))
    setGridApi(params.api);
    setColumnApi(params.columnApi);
  };

  return (
    <div className="ag-theme-alpine demo-grid-wrap">
      <AgGridReact
        onGridReady={(params) => {
          onGridReady(params);
        }}
        immutableData={true}
        rowData={gridStateData}
        getRowNodeId={node => node.id}
        modules={AllModules}
        onCellValueChanged={handleCellChange}
        defaultColDef={{
          resizable: true,
          sortable: true,
          filter: true,
          headerComponentFramework: LoadHeaderComponent,
          headerComponentParams: {
            menuIcon: "fa-bars",
          },
        }}
      >

        <AgGridColumn headerName="#" width={50} checkboxSelection sortable={false} suppressMenu filter={false} pinned></AgGridColumn>

        <AgGridColumn headerName="Load Details" headerGroupComponentFramework={HeaderGroupComponent}>
          <AgGridColumn field="dis" width={110} headerName="Dispatch" editable  cellClass="dispatch" valueSetter={dataSetter} />
          <AgGridColumn field="hour" width={50} headerName="Hour" cellClass="hour" />
        </AgGridColumn>

      </AgGridReact>
    </div>
  );
};

const rules = {
  dc_rules:{
    "cell-blue": (params: { value: string }) => params.value === 'ERD',
    "cell-beige": (params: {value: string }) => params.value === 'PDC',
    "cell-cyan": (params: {value: string }) => params.value === 'CRD'
  },
  nr_cube_rules:{
    "cell-red": (params: {value: number }) => params.value > 10.0
  }
}

export default LoadSchedulerGrid;
 

Ответ №1:

Ag-grid по умолчанию пытается напрямую изменить объект состояния за пределами редуктора. Вы должны использовать настройку Ag-сетки immutableData .

https://www.ag-grid.com/javascript-data-grid/immutable-data/

У них даже есть статья в блоге об использовании RTK с Ag-сеткой (даже если они используют неизменяемую логику в редукторах — в редукторах RTK это не обязательно, как вы правильно заметили): https://blog.ag-grid.com/adding-removing-rows-columns-ag-grid-with-react-redux-toolkit/

Комментарии:

1. Я добавил неизменяемый тип данных, а также функцию getRowID, но ошибка по-прежнему сохраняется. Я попытался следовать учебнику и все еще застрял. Буду признателен за любую дальнейшую помощь. Я могу успешно загружать данные из хранилища, просто не удается, как только я редактирую ячейку ( даже без вызова обработчика onCellChange).

2. Можете ли вы обновить примеры кода и, возможно, даже предоставить воспроизведение?

3. Примеры кода в вопросе были обновлены.

4. Вам нужно будет написать valueSetter метод в вашем столбце, и это нужно сделать return false в конце, иначе ag-grid все равно попытается написать на объекте.

5. Вы не можете изменить объект непосредственно в этом методе набора данных, так как он находится в состоянии восстановления, и вы можете изменить состояние восстановления только путем отправки действия. (Так что вам придется отправить сюда…) Вы уверены, что хотите сохранить его в Redux здесь в первую очередь? В этом случае было бы лучше сохранить его в состоянии локального компонента.