Redux Toolkit is a popular library that simplifies Redux development by providing a set of utilities and conventions. It includes a reducer and action creation patterns that streamline the process of writing Redux logic. Combining Redux Persist with Redux Toolkit can significantly enhance the efficiency and reliability of state management in your React Native apps.
expo-file-system
provides access to a file system stored locally on the device. It is also capable of uploading and downloading files from network URLs
redux-persist-expo-file-system-storage
is a storage engine for redux-persist
that uses Expo's File System API. This allows you to persist your Redux store's state to the device's file system, ensuring that the state is saved and restored even if the app is closed or restarted.
Once you have configured your Redux Toolkit store, you can integrate Redux Persist. Begin by installing the necessary dependencies:
npm i @reduxjs/toolkit
npm i expo-file-system
npm i redux-persist-expo-file-system-storage
npm i redux-persist
we create a simple Redux store @reduxjs/toolkit
to manage a counter state. We define an initial state with a count of 0 and create a slice named counter with two reducers: increment
and decrement
, which increase and decrease the count by 1, respectively. The actions and the reducer are exported for use in our Redux setup, allowing us to easily manage the counter state throughout the application.
// store/counter/counter.tsx
import { createSlice } from "@reduxjs/toolkit";
const initialState = {
count: 0,
};
const counterSlice = createSlice({
name: "couter",
initialState,
reducers: {
increment: (state) => {
state.count += 1;
},
decrement: (state) => {
state.count -= 1;
},
},
});
export const { increment, decrement } = counterSlice.actions;
export default counterSlice.reducer;
The code sets up a Redux store in a React Native app using @reduxjs/toolkit
and redux-persist
with Expo's FileSystem for persistent storage. It combines reducers, including a counter reducer, and ensures their state is saved and loaded from a specified directory within the app's file system.
// store/ConfigureStore.js
import { combineReducers } from "@reduxjs/toolkit";
import { documentDirectory, EncodingType } from "expo-file-system";
import { createExpoFileSystemStorage } from "redux-persist-expo-file-system-storage";
import CounterReducer from "./counter/counter";
import { persistReducer } from "redux-persist";
console.log('Document Directory:',documentDirectory);
export const expoFileSystemStorage = createExpoFileSystemStorage({
storagePath: `${documentDirectory}customPathName/`,
encoding: EncodingType.UTF8,
debug: true,
});
const persist = (key, reducer) =>
persistReducer(
{
key,
storage: expoFileSystemStorage,
},
reducer
);
const combinePersistReducers = (keys) =>
Object.keys(keys).reduce(
(obj, key) => ({
...obj,
[key]: persist(key, keys[key]),
}),
{}
);
const reducers = combineReducers({
...combinePersistReducers({
count: CounterReducer,
}),
});
export default reducers;
In this part of the setup, we configure and create the Redux store using @reduxjs/toolkit
. We import the rootReducer
that combines our reducers and disable the serializableCheck
middleware to prevent serialization errors from redux-persist
. We also set up redux-persist
to enable state persistence and export both the store and the persistor for integration with our React Native application. This configuration ensures our app's state is maintained even after it is closed or refreshed.
// store/index.js
import { configureStore } from "@reduxjs/toolkit";
import { persistStore } from "redux-persist";
import { Provider } from "react-redux";
import rootReducer from "./ConfigureStore";
const store = configureStore({
reducer: rootReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: false,
}),
});
const persistor = persistStore(store);
export { store, persistor };
By logging and understanding the documentDirectory
path in the configureStore file, you gain valuable insight into where your Redux Persist data is stored in an Expo environment. This knowledge not only helps in debugging but also ensures that your data persistence strategy is robust and secure. Now you can confidently manage your app's state, knowing exactly where your data lives.
Within this directory, redux-persist
will store your persisted state. Typically, the persisted data is stored in a file named persist-counter
(or something similar, depending on your configuration). Here’s how you can navigate to and view this file:
// persist-count file
{"count":"0","_persist":"{\"version\":-1,\"rehydrated\":true}"}
For a complete example, you can check out the GitHub repository for this project: GitHub Repository Link
💬 I’d love to hear your thoughts on this topic! If you have any questions about using Expo File System with Redux Persist, or if you run into any issues, please drop a comment below. I’m here to help! 😄
Top comments (4)
is this similar to async storage ?
Yes, it's the same as that both expo File System storage and Async Storage can be used to persist redux state across apps.
File system might be advantageous if your app have to handle larger or more complex data
i have now used react-native-mmkv which is swift n doesn't need async call does it work similarly to that as well
Yes, most probably it will be working similarly to this just we have to configure it properly to achieve this functionality