9

i'm having a table component for displaying some data. After dispatching an action the table data in the state are channging. However my table component is not updated. It is updated only when i click on another radio button in another row of my table. I want my component to rerender when the data are changed. Here is my code:

const mapStateToProps = state => ({
  evaluationData: evaluationResultsSelector(state)
});

const mapDispatchToProps = dispatch => ({
  setSelectedEvaluationRecord: record =>
    dispatch(setSelectedEvaluationRecord(record))
});


export default connect(mapStateToProps,
  mapDispatchToProps
  EvaluationDataTable,  
);

and my component is this:

import React from 'react';
import Table from 'antd/lib/table';
import 'antd/lib/table/style/css';
import "antd/dist/antd.css";
import { columnEvaluation } from './evaluationDataStructure';

class EvaluationDataTable extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      selectedRowKeys: [0], // Check here to configure the default column
    };
  }
  // shouldComponentUpdate(prevProps, prevState) {
  //   return (prevProps.results !== this.props.results || prevState.selectedRowKeys !== this.state.selectedRowKeys);
  // }
  onRowChange = selectedRowKeys => {
    if (selectedRowKeys.length > 1) {
      const lastSelectedRowIndex = [...selectedRowKeys].pop();
      this.setState({ selectedRowKeys: lastSelectedRowIndex });
    }
    this.setState({ selectedRowKeys });
  };

  onRowSelect = (record) => {
    this.props.setSelectedEvaluationRecord(record)
  };

  render() {
    const { selectedRowKeys } = this.state;
    const rowSelection = {
      type: 'radio',
      selectedRowKeys,
      onChange: this.onRowChange,
      onSelect: this.onRowSelect
    };
    return (
      <React.Fragment>
        <div style={{ marginBottom: 16 }} />
        <Table
          rowSelection={rowSelection}
          columns={columnEvaluation}
          dataSource={this.props.evaluationData}
        />
      </React.Fragment>
    );
  }
}

export default EvaluationDataTable;

When i click in another row the table is rerendered as my setState is triggered but when the data are channged the table is not rerendered. Only when i click in another row. How to deal with it? Thanks a lot

Also my reducer which mutates the table is this:

case ACTION_TYPES.EDIT_EVALUATION_RESULTS: {
      const evaluationResults = state.evaluationResults;
      const editedRecord = action.payload.editedEvaluationData;
      evaluationResults.forEach((item, i)  => {
        if (item.id === editedRecord.id) {
          evaluationResults[i] = editedRecord;
        }
      });
      return {
        ...state,
        evaluationResults
      };
    }
RamAlx
  • 6,976
  • 23
  • 58
  • 106
  • 1
    Problem likely has something to do with your reducer setup. Can you post your code for it? – Chris Ngo May 25 '19 at 19:07
  • my reducer works fine, when I edit a row and click the button the state is changing properly. The problem is that the component is not re rendering after state change – RamAlx May 26 '19 at 00:05
  • Check the updated question – RamAlx May 26 '19 at 00:19
  • 1
    @ChristopherNgo you were so right..i change this evaluationResults to this evaluationResults : [...evaluationResults] – RamAlx May 26 '19 at 00:42
  • 1
    haha yeah I saw that... you were doing a state-mutation. I was just going to tell you to spread it in a new array instead. I'm glad you took the time to figure it out and learned a little more about redux-principles. – Chris Ngo May 26 '19 at 00:43
  • 1
    Thanks a lot!! If you want add this as an answer so as to gain more points. ;) – RamAlx May 26 '19 at 00:45
  • 1
    That is very much appreciated :) – Chris Ngo May 26 '19 at 00:46

1 Answers1

15

Problem was here as OP has already deduced.

 const evaluationResults = state.evaluationResults;

This was causing a state-mutation which goes against Redux principles. Although the state values were being updated in OP's proceeding code, the changes were being made to the same, initial object in reference. Redux does not register it as a new-state so it found no need to re-render our component. To get your connected-component to re-render we need a completely new redux-state.

To achieve this, we need to create a brand-new copy of evaluationResults like so and then the OP's feature will work as expected:

const evaluationResults = [...state.evaluationResults];
Chris Ngo
  • 15,460
  • 3
  • 23
  • 46