Skip to content

Redux Saga flow stops after first dispatched action when using @rozenite/redux-devtools-plugin #160

@safinghoghabori

Description

@safinghoghabori

Describe the bug

After successfully integrating @rozenite/network-activity-plugin i was trying to integrate @rozenite/redux-devtools-plugin. App compiles and builds successfully but when I perform any action in the app that makes an API call, Redux Saga flows stops after the first dispatched action.

For example, on login:

  • login/loginStart is dispatched
  • No subsequent actions (loginSuccess, loginFailure) are ever dispatched
  • API call is also not triggered (because not able to see it in Network tab)

The app does not freeze and does not crash, but async flow never completes.

Disabling the Rozenite Redux DevTools enhancer immediately restores correct saga behavior. I'm able to integrate @rozenite/network-activity-plugin alone successfully and it shows API logs in Network tab.

Attaching my store and metro configuration here hoping maybe you guys have a clue on what I might have not been doing correctly.

// store.ts

import {createStore} from 'redux-dynamic-modules';
import {compose, type StoreEnhancer} from 'redux';
import createSagaMiddleware from 'redux-saga';
import {rozeniteDevToolsEnhancer} from '@rozenite/redux-devtools-plugin';

import type {SagaMiddleware} from 'redux-saga';
import type {IModule, IModuleStore} from 'redux-dynamic-modules';

/* -------------------- Enhancers -------------------- */

const enhancers: StoreEnhancer[] = [];

if (__DEV__) {
  enhancers.push(rozeniteDevToolsEnhancer());
}

/* -------------------- Saga middleware -------------------- */

const sagaMiddleware = createSagaMiddleware();

/* -------------------- Compose enhancers -------------------- */

const composedEnhancer =
  enhancers.length > 0 ? compose(...enhancers) : undefined;

/* -------------------- Store -------------------- */

type IState = unknown;

const store: IModuleStore<IState> = createStore({
  initialState: {},
  enhancers: composedEnhancer ? [composedEnhancer] : [],
  extensions: [getCustomSagaExtension(sagaMiddleware)],
});

/* Debug access (safe for RN) */
if (__DEV__ && typeof global !== 'undefined') {
  // @ts-ignore
  global.store = store;
}

export default store;

/* -------------------- Dynamic Saga Extension -------------------- */

function getCustomSagaExtension(
  sagaMiddleware: SagaMiddleware<object>,
): IExtension {
  return {
    middleware: [sagaMiddleware],
    enhancers: [],
    onModuleAdded: (module: IModule<{sagas: unknown[]}>) => {
      if (module?.sagas?.length) {
        module.sagas.forEach(sagaMiddleware.run);
      }
    },
  };
}

interface IExtension {
  middleware: unknown[];
  enhancers: unknown[];
  onModuleAdded: (module: IModule<{sagas: unknown[]}>) => void;
}

// metro.config.js

/* eslint-disable @typescript-eslint/no-var-requires */
const {withRozenite} = require('@rozenite/metro');
const {
  withRozeniteReduxDevTools,
} = require('@rozenite/redux-devtools-plugin/metro');

const {getDefaultConfig} = require('expo/metro-config');
const {mergeConfig} = require('@react-native/metro-config');
const blacklist = require('metro-config/src/defaults/exclusionList');
const {withSentryConfig} = require('@sentry/react-native/metro');
const {
  wrapWithReanimatedMetroConfig,
} = require('react-native-reanimated/metro-config');

const defaultConfig = getDefaultConfig(__dirname);
const {
  resolver: {sourceExts, assetExts},
} = defaultConfig;

const config = {
  transformer: {
    babelTransformerPath: require.resolve('react-native-svg-transformer'),
    getTransformOptions: async () => ({
      transform: {
        experimentalImportSupport: false,
        inlineRequires: false,
      },
    }),
  },
  resolver: {
    assetExts: assetExts.filter(ext => ext !== 'svg'),
    sourceExts: [...sourceExts, 'svg'],
    blacklistRE: blacklist([
     ...
    ]),
    resolverMainFields: ['sbmodern', 'react-native', 'browser', 'main'],
  },
};

module.exports = withRozenite(
  wrapWithReanimatedMetroConfig(
    withSentryConfig(mergeConfig(defaultConfig, config)),
  ),
  {
    enhanceMetroConfig: withRozeniteReduxDevTools,
    enabled: true,
  },
);

PS: Earlier i was using reactotron and its configuration was added, however due to this issue i removed it thinking two subscriptions to the redux store may be causing an issue. Let me know if i can add more details.

System Info

System:
  OS: macOS 26.0.1
  CPU: (11) arm64 Apple M3 Pro
  Memory: 164.81 MB / 18.00 GB
  Shell:
    version: "5.9"
    path: /bin/zsh
Binaries:
  Node:
    version: 22.18.0
    path: ~/.nvm/versions/node/v22.18.0/bin/node
  Yarn:
    version: 4.9.2
    path: ~/.nvm/versions/node/v22.18.0/bin/yarn
  npm:
    version: 10.9.3
    path: ~/.nvm/versions/node/v22.18.0/bin/npm
  Watchman: Not Found
Managers:
  CocoaPods:
    version: 1.16.2
    path: /opt/homebrew/bin/pod
SDKs:
  iOS SDK:
    Platforms:
      - DriverKit 25.0
      - iOS 26.0
      - macOS 26.0
      - tvOS 26.0
      - visionOS 26.0
      - watchOS 26.0
  Android SDK: Not Found
IDEs:
  Android Studio: 2025.1 AI-251.26094.121.2512.13840223
  Xcode:
    version: 26.0.1/17A400
    path: /usr/bin/xcodebuild
Languages:
  Java:
    version: 17.0.16
    path: /usr/bin/javac
  Ruby:
    version: 2.6.10
    path: /usr/bin/ruby
npmPackages:
  "@react-native-community/cli":
    installed: 15.0.1
    wanted: 15.0.1
  react:
    installed: 18.3.1
    wanted: 18.3.1
  react-native:
    installed: 0.76.9
    wanted: 0.76.9
  react-native-macos: Not Found
npmGlobalPackages:
  "*react-native*": Not Found
Android:
  hermesEnabled: true
  newArchEnabled: false
iOS:
  hermesEnabled: true
  newArchEnabled: false

Rozenite Version

1.1.0

Reproduction

private

Steps to reproduce

see above

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions