DEV Community

Cover image for React Native Redux(SAGA/THUNK/TOOLKIT) Setup With Reactotron
Ajmal Hasan
Ajmal Hasan

Posted on • Edited on

React Native Redux(SAGA/THUNK/TOOLKIT) Setup With Reactotron

Introduction

  • React Native
    : React Native is a popular open-source framework developed by
    Facebook. It allows you to build native mobile applications using JavaScript and React. With React Native, you can write code once and deploy it on both iOS and Android platforms, reducing development time and effort.

  • Redux
    : Redux is a predictable state container for JavaScript applications. It provides a centralized store to manage the state of your application. Redux follows a unidirectional data flow pattern, making it easier to understand and debug complex application states.

  • Redux Saga
    : Redux Saga is a middleware library for Redux. It focuses on managing side effects, such as asynchronous actions, in a more elegant and testable way. It uses generator functions to handle complex asynchronous flows, allowing you to write non-blocking code that is easier to reason about.

  • Redux Persist
    : Redux Persist is a library that integrates with Redux to persist the Redux store's state across sessions. It allows you to save and load the state to and from storage, such as AsyncStorage in React Native or localStorage in web browsers. This feature is useful for maintaining application state even after a user closes and reopens the app.

  • Reactotron
    : Reactotron is a desktop application that helps with debugging and monitoring React and React Native applications. It provides a range of features, such as inspecting the state and actions dispatched to Redux, displaying network requests, and logging custom messages. Reactotron makes it easier to identify and fix bugs during development.

These tools and libraries are commonly used in React Native development to
simplify state management, handle asynchronous actions, persist state, and
enhance the debugging experience.

Reactotron Official Site: https://github.com/infinitered/reactotron

Reactotron Desktop application: https://github.com/infinitered/reactotron/releases

Reactotron is a macOS, Windows, and Linux app for inspecting your React JS and React Native apps.

Use it to:

  • 1. view your application state
  • 2. show API requests & responses
  • 3. perform quick performance benchmarks
  • 4. subscribe to parts of your application state
  • 5. display messages similar to console.log
  • 6. track global errors with source-mapped stack traces including saga stack traces!
  • 7. dispatch actions like a government-run mind control experiment
  • 8. hot swap your app's state using Redux or mobx-state-tree
  • 9. track your sagas
  • 10. show image overlay in React Native
  • 11. track your Async Storage in React Native

Image description

Image description


For React.js refer this link


Setup for app with redux saga:

1) Dependencies to install:

yarn add reactotron-react-native reactotron-redux reactotron-redux-saga -D

2) Reactotron Config file:

Create a file ReactotronConfig.js and Paste below code:

import Reactotron, { networking } from 'reactotron-react-native';
import sagaPlugin from 'reactotron-redux-saga';
import { reactotronRedux } from 'reactotron-redux';
import AsyncStorage from '@react-native-async-storage/async-storage';

const IGNORED_API_URLS = ['https://clients3.google.com/generate_204'];

Reactotron.configure({ name: 'app_name' })
  .setAsyncStorageHandler(AsyncStorage)
  .useReactNative()
  .use(sagaPlugin())
  .use(
    networking({
      ignoreContentTypes: /^(image)\/.*$/i,
      ignoreUrls: [...IGNORED_API_URLS, /\/(logs|symbolicate)$/],
      ignoreRequests: (request) => IGNORED_API_URLS.some((url) => request.url.includes(url)),
    })
  )
  .use(
    networking({
      ignoreContentTypes: /^(image)\/.*$/i,
      ignoreUrls: [...IGNORED_API_URLS, /\/(logs|symbolicate)$/],
      ignoreRequests: (request) => IGNORED_API_URLS.some((url) => request.url.includes(url)),
    })
  )
  .use(reactotronRedux()) //  <- here i am!
  .connect();

//  patch console.log to send log to reactotron
const yeOldeConsoleLog = console.log;
console.log = (...args) => {
  yeOldeConsoleLog(...args);
  Reactotron.display({
    name: 'CONSOLE.LOG',
    value: args,
    preview: args.length > 0 && typeof args[0] === 'string' ? args[0] : null,
  });
};

export default Reactotron;

Enter fullscreen mode Exit fullscreen mode
3) Finally import and add it to redux store:

REDUX PERSIST CONFIGURATION

import Reactotron from '../config/ReactotronConfig';

import { createStore, applyMiddleware, compose } from 'redux';
import { persistStore, persistReducer } from 'redux-persist';
import createSagaMiddleware from 'redux-saga';
import AsyncStorage from '@react-native-async-storage/async-storage';
import Reactotron from '../config/ReactotronConfig';
import combineReducers from './reducers';
import { rootSaga } from './sagas';

let store,
  persistor,
  persistConfig,
  sagaMiddleware,
  middleware,
  persistedReducer,
  sagaMonitor,
  enhancer;

persistConfig = {
  key: 'root',
  storage: AsyncStorage,
  blacklist: ['authReducer'], //these reduce will not persist data
  whitelist: ['homeReducer'], //these reduce will persist data
};

if (!__DEV__) {
  // Middleware: Redux Saga
  sagaMiddleware = createSagaMiddleware();
  middleware = applyMiddleware(sagaMiddleware);
  persistedReducer = persistReducer(persistConfig, combineReducers);
  // Redux: Store
  store = createStore(persistedReducer, middleware);
} else {
  sagaMonitor = Reactotron.createSagaMonitor();
  sagaMiddleware = createSagaMiddleware({ sagaMonitor });
  middleware = applyMiddleware(sagaMiddleware);
  enhancer = compose(middleware, Reactotron.createEnhancer());
  persistedReducer = persistReducer(persistConfig, combineReducers);
  store = createStore(persistedReducer, enhancer);
}

sagaMiddleware.run(rootSaga);
persistor = persistStore(store);

export { store, persistor };
Enter fullscreen mode Exit fullscreen mode

NON REDUX PERSIST CONFIGURATION

import { createStore, applyMiddleware, compose } from 'redux';
import createSagaMiddleware from 'redux-saga';
import Reactotron from '../config/ReactotronConfig';
import combineReducers from './reducers';
import { rootSaga } from './sagas';

let store;

if (!__DEV__) {
    // Middleware: Redux Saga
    sagaMiddleware = createSagaMiddleware();
    middleware = applyMiddleware(sagaMiddleware);
    // Redux: Store
    store = createStore(
        combineReducers,
        middleware,
    )
} else {
    sagaMonitor = Reactotron.createSagaMonitor();
    sagaMiddleware = createSagaMiddleware({ sagaMonitor });
    middleware = applyMiddleware(sagaMiddleware);
    enhancer = compose(middleware, Reactotron.createEnhancer());
    store = createStore(combineReducers, enhancer)
}

sagaMiddleware.run(rootSaga);

export { store };

Enter fullscreen mode Exit fullscreen mode

Image


Setup for app with redux thunk:

1) Dependencies to install:

yarn add reactotron-react-native reactotron-redux -D

2) Reactotron Config file:

Create a file ReactotronConfig.js and Paste below code:

import Reactotron, { networking } from 'reactotron-react-native';
import sagaPlugin from 'reactotron-redux-saga';
import { reactotronRedux } from 'reactotron-redux';
import AsyncStorage from '@react-native-async-storage/async-storage';
const IGNORED_API_URLS = ['https://clients3.google.com/generate_204'];

Reactotron.configure({ name: 'app_name' })
  .setAsyncStorageHandler(AsyncStorage)
  .useReactNative()
  .use(
    networking({
      ignoreContentTypes: /^(image)\/.*$/i,
      ignoreUrls: [...IGNORED_API_URLS, /\/(logs|symbolicate)$/],
      ignoreRequests: (request) => IGNORED_API_URLS.some((url) => request.url.includes(url)),
    })
  )
  .use(reactotronRedux()) //  <- here i am!
  .connect();


//  patch console.log to send log to reactotron
const yeOldeConsoleLog = console.log;
console.log = (...args) => {
  yeOldeConsoleLog(...args);
  Reactotron.display({
    name: 'CONSOLE.LOG',
    value: args,
    preview: args.length > 0 && typeof args[0] === 'string' ? args[0] : null,
  });
};

export default Reactotron;
Enter fullscreen mode Exit fullscreen mode
3) Finally import and add it to redux store:
const enhancer = compose(
  middleware,
  Reactotron.createEnhancer(),
);
Enter fullscreen mode Exit fullscreen mode

Setup for app with redux toolkit without persist:

store.js

import {configureStore} from '@reduxjs/toolkit';
import cakeReducer from './slices/cakeSlice';
import userReducer from './slices/userSlice';
import Reactotron from '../Reactotron/ReactotronConfig';
import logger from 'redux-logger';

const store = configureStore({
  reducer: {
    cake: cakeReducer,
    users: userReducer,
  },
  middleware: getDefaultMiddleware => getDefaultMiddleware(),
  // middleware: getDefaultMiddleware => getDefaultMiddleware().concat(logger),
  enhancers: [Reactotron.createEnhancer()],
  devTools: true,
});
export default store;
Enter fullscreen mode Exit fullscreen mode

Setup for app with redux toolkit with persist:

Github Url

store.js

import {combineReducers, configureStore} from '@reduxjs/toolkit';
import cakeReducer from './slices/cakeSlice';
import icecreamReducer from './slices/icecreamSlice';
import userReducer from './slices/userSlice';
import Reactotron from '../Reactotron/ReactotronConfig';
import {
  persistReducer,
  FLUSH,
  REHYDRATE,
  PAUSE,
  PERSIST,
  PURGE,
  REGISTER,
} from 'redux-persist';
import AsyncStorage from '@react-native-async-storage/async-storage';
import logger from 'redux-logger';

const persistConfig = {
  key: 'root',
  version: 1,
  storage: AsyncStorage,
};
const reducer = combineReducers({
  cake: cakeReducer,
  icecream: icecreamReducer,
  users: userReducer,
});
const persistedReducer = persistReducer(persistConfig, reducer);

const store = configureStore({
  reducer: persistedReducer,
  middleware: getDefaultMiddleware =>
    getDefaultMiddleware({
      serializableCheck: {
        ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
      },
    }),
  // middleware: getDefaultMiddleware => getDefaultMiddleware().concat(logger),
  enhancers: [Reactotron.createEnhancer()],
  devTools: true,
});

export default store;

Enter fullscreen mode Exit fullscreen mode

App.js

import React from 'react';
import {Provider} from 'react-redux';
import {PersistGate} from 'redux-persist/integration/react';
import {persistStore} from 'redux-persist';
// import store from './redux/store';
import rtkStore from './reduxToolkit/store';
import HomeScreen from './screens/home';

let persistor = persistStore(rtkStore);

const App = () => {
  return (
    <Provider store={rtkStore}>
      <PersistGate loading={null} persistor={persistor}>
        <HomeScreen />
      </PersistGate>
    </Provider>
  );
};
export default App;
Enter fullscreen mode Exit fullscreen mode

Note:
Sometimes redux store is not visible in reactotron. So in that case simply click on top right corner ➕ button then a popup appears, now click enter button from keyboard.

Top comments (0)