Search code examples
typescriptreduxredux-toolkit

Is it possible to listen for a state change and action at the same time with the redux toolkit listenerMiddleware


I need to trigger the same function two times. Once after a certain redux state changed and once after a redux action is fulfilled. Currently I use two separate listeners for it. I was wondering if it is possible to combine the predicate and the actionCreator into one listener. I tried but was not able to make it work.

listener middleware docs for reference: https://redux-toolkit.js.org/api/createListenerMiddleware

Current implementation (works fine):

export const addTemperatureAlertListener2 = (
  startListening: AppStartListening
) => {
  startListening({
    predicate: (action, currentState, originalState) => {
      return (
        currentState.chart.yLimits.yMax !== originalState.chart.yLimits.yMax ||
        currentState.chart.yLimits.yMin !== originalState.chart.yLimits.yMin ||
        currentState.user.tConfig.alertHigherThreshold !==
          originalState.user.tConfig.alertHigherThreshold
      );
    },
    effect: (action, listenerApi) => {
      temperatureAlertEffect(action, listenerApi);
    },
  });
};

export const addTemperatureAlertListener1 = (
  startListening: AppStartListening
) => {
  startListening({
    actionCreator: createPatchRecord.fulfilled,
    effect: (action, listenerApi) => {
      temperatureAlertEffect(action, listenerApi);
    },
  });
};

What I tried but did not work:

export const addTemperatureAlertListener = (
  startListening: AppStartListening
) => {
  startListening({
    actionCreator: createPatchRecord.fulfilled,
    predicate: (action, currentState, originalState) => {
      return (
        currentState.chart.yLimits.yMax !== originalState.chart.yLimits.yMax ||
        currentState.chart.yLimits.yMin !== originalState.chart.yLimits.yMin ||
        currentState.user.tConfig.alertHigherThreshold !==
          originalState.user.tConfig.alertHigherThreshold
      );
    },
    effect: (action, listenerApi) => {
      temperatureAlertEffect(action, listenerApi);
    },
  });
};

Solution

  • I was wondering if it is possible to combine the "predicate" and the "actionCreator" into one listener.

    No, you cannot merge the listeners. See startListening for details.

    You must provide exactly one of the four options for deciding when the listener will run: type, actionCreator, matcher, or predicate.

    This means each listener middleware can only select one of the above and the effect callback.

    What you might be able to do is to "partially" merge them, i.e. a single function that instantiates both listeners.

    export const addTemperatureAlertListener = (
      startListening: AppStartListening
    ) => {
      startListening({
        predicate: (action, currentState, originalState) => {
          return (
            currentState.chart.yLimits.yMax !== originalState.chart.yLimits.yMax ||
            currentState.chart.yLimits.yMin !== originalState.chart.yLimits.yMin ||
            currentState.user.tConfig.alertHigherThreshold !==
              originalState.user.tConfig.alertHigherThreshold
          );
        },
        effect: temperatureAlertEffect,
      });
    
      startListening({
        actionCreator: createPatchRecord.fulfilled,
        effect: temperatureAlertEffect,
      });
    };