CountGradsky
CountGradsky

Reputation: 268

mapStateToProps not updating component on change

New to react/redux. Wondering why my component is not refreshing on the fired action. Also not sure whether reducer is a good place to manipulate the store but it is pure so it should work.

What happens is that action is fired and store is updated. But the clicked item is not updating (props update shoud add class added to it)

Component:

Referencing rcm_data by Id to toggle class added, onClick fire action

import React, { Component } from "react";
import { connect } from "react-redux";
import { addRateCard } from "../actions";

import "./RcmEditor.css";

class RcmEditor extends Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
      <table className="slds-table slds-table--cell-buffer slds-table--bordered">
        <thead>
          <tr>
            <th>Rate Card Name</th>
          </tr>
        </thead>
        <tbody>
          {group.rateCardIds.map(rcId => {
            return (
              <tr
                className={
                  "ed-group-rc " +
                  (this.props.rcm_data[rcId].added ? "added" : "")
                }
                key={rcId}
                onClick={() =>
                  this.props.addRateCard(this.props.rcm_data[rcId])
                }
              >
                <td colSpan="100">{this.props.rcm_data[rcId].Name}</td>
              </tr>
            );
          })}
        </tbody>
      </table>
    );
  }
}

const mapDispatchToProps = {
  addRateCard
};

const mapStateToProps = state => {
  return { rcm_data: state.rcm_data, group_data: state.group_data };
};

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(RcmEditor);

Actions:

const ADD_RATE_CARD = "ADD_RATE_CARD";

export const addRateCard = rateCard => ({ type: ADD_RATE_CARD, payload: rateCard });

Reducer:

Copy state (just a precaution), increment added_count property of group_data and change added property of rcm_data referenced by action. payload Id, return a new state. Everything seems pure here

const initialState = {
    rcm_data: {},
    group_data: {},
};

const rootReducer = (state = initialState, action) => {
    case "ADD_RATE_CARD":

        let _state = { ...state };
        let rateCard = action.payload;

        _state.group_data[rateCard.GroupName].added_count++;
        _state.rcm_data[rateCard.Id].added = true;

        let data = {
            rcm_data: _state.rcm_data,
            group_data: _state.group_data
        };

        return { ...state, rcm_data: _state.rcm_data, group_data: _state.group_data };
    default:
        return state;
   }
};

export default rootReducer;

Upvotes: 0

Views: 1647

Answers (1)

xadm
xadm

Reputation: 8418

Your reducer copies objects (rcm_data and group_data) and mutates them.

Redux compares shallowly - using the same object refs there is no difference then no update/rerender.

Simply create a new sub-objects, sth like:

    let data = {
        rcm_data: {...state.rcm_data},
        group_data: {...state.group_data}
    };
    data.group_data[rateCard.GroupName].added_count++;
    data.rcm_data[rateCard.Id].added = true;
    return data

Upvotes: 4

Related Questions