Tell React/Redux to ignore object references and just do a deep equality check

Viewed 439

Problem - my component is updating even if the input data hasn't changed and I suspect it's because an object ref change while a deep compare didn't change.

I have a reducer like so:

const getDefaultState = () => ({
  mainNotifMessage: '(unknown message)',
  notifDetails: '(unknown notification details)',
  snackBarOpen: true
});

export type CPAction = {type: string, val: object}

export const notifsReducer = (state = getDefaultState(), action: CPAction) => {

  switch (action.type) {
    case c.NOTIFY_ERROR:

      return {
        ...state,
        ...action.val
      };

    default:
      return {
        ...state
      };
  }
};

and then in an component I have:

function mapStateToProps(state: RootState) {
  return {
    notifs: state.notifs
  };
}

I think what happens is that state.notif always gets a new object reference, so React/Redux is always updating my component even if there are no changes. But if I change it to this:

function mapStateToProps(state: RootState) {
  return {
    mainNotifMessage: state.notifs.mainNotifMessage,
    snackBarOpen: state.notifs.snackBarOpen,
    severity: state.notifs.severity,
    notifDetails: state.notifs.notifDetails
  };
}

then it doesn't update the components. Is there a way to tell Redux/React to always to do a deep compare and not return early on object reference differences?

1 Answers

I think what happens is that state.notif always gets a new object reference, so React/Redux is always updating my component even if there are no changes.

By default, React-Redux decides whether the contents of the object returned from mapStateToProps are different using === comparison (a "shallow equality" check) on each fields of the returned object.

 default:
  return {
    ...state
  };

You are returning a new reference each time in your default state. So when you read values using dot notation, you get the same values.

But for Javascript, it is a new object reference, hence React-Redux will try to re-render the component.

You can just do return state instead of spreading it and creating a new object reference in the default case of your reducer.

Reference : https://react-redux.js.org/using-react-redux/connect-mapstate#return-values-determine-if-your-component-re-renders

Related