React Native Redux(SAGA/THUNK/TOOLKIT) Setup With Reactotron
Ajmal Hasan
Posted on September 23, 2021
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
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;
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 };
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 };
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;
3) Finally import and add it to redux store:
const enhancer = compose(
middleware,
Reactotron.createEnhancer(),
);
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;
Setup for app with redux toolkit with persist:
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;
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;
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.
Posted on September 23, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.