Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.2k views
in Technique[技术] by (71.8m points)

reactjs - agGrid in react + redux app is modifying underlying data

I'm using latest agGrid enterprise in react + redux app.

The issue is that I'm using built in editing of agGrid and this is modifying directly underlying data i.e. array that is returned from redux store. This is breaking immutability principle. Is there way to use/configure agGrid no to modify the data but to:

  • react to change and call some callback with info about the change
  • then I could update redux store (one item in the array)
  • then agGrid could detect that only single object in array got changed and it would refresh only single row

Thanks

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

EDIT: Expanding my answer with more detail.

You have to set a "valueSetter" function, and set it on each column. Easiest way to do that is with the defaultColDef. Quick note, each row in my table is a 'transaction', so you'll see reference to transactions, versus some other form of identification.

For example:

<AgGridReact
      // OPTIONS REQUIRED FOR OPTIMIZATION WITH REACT
      reactNext
      deltaRowDataMode
      getRowNodeId={data => data.transaction_id}

      // OTHER OPTIONS
      rowSelection="multiple"
      editType="fullRow"

      // TABLE DATA
      defaultColDef={{ ...defaultColDef, valueSetter }}
      columnDefs={columns}
      rowData={transactions}

      // DISPLAY
      rowClassRules={rowClassRules}

       // EVENTS
      onGridReady={onGridReady}
      onRowEditingStarted={onRowEditingStarted}
      onRowEditingStopped={onRowEditingStopped}

    />

Don't forget the optimization items required for react and redux. (reactNext, deltaRowDataMode, getRowNodeId).

The defaultColDef I have defined is simple:

defaultColDef: {
  resizable: true,
  sortable: true,
  filter: true,
  editable: true,
},

And the valueSetter is a function defined very simply as:

const valueSetter = (params) => {
  allActions.columnEdit(params.data, params.oldValue, params.newValue, params.colDef);
  return false;
};

Where the allActions.columnEdit is just calling my Redux action I have defined in an import and then bound with connect() and mapDispatchToProps. The return false is what's required to prevent the mutating of the state. Make sure that your redux action handles whatever you need to do. Here's my example:

  case actionTypes.COLUMN_EDIT: {
  // FOR EACH COLUMN EDITED, CHECK IF ANYTHING CHANGED
  // POST CHANGES TO NEW STATE
  if (payload.oldValue !== payload.newValue) {
    const account = 'acct01';
    const column = payload.colDef.field;
    const index = state[account].transactions.findIndex(
      t => t.transaction_id === payload.t.transaction_id,
    );
    return produce(state, (draft) => {
      const transaction = draft[account].transactions[index];
      transaction[column] = payload.newValue;
    });
  }
  return state;
}

Hope this helps. Seems to be a LOT of extra workaround for what should be handled directly by Ag-Grid, but maybe they'll put some future development into it.

https://www.ag-grid.com/javascript-grid-value-setters/


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...