blog bg

December 04, 2023

Simplified Global State Management and API Requests in React Typescript: Enhancing User Experience with redux-persist (Part Two)

Share what you learn in this blog to prepare for your interview, create your forever-free profile now, and explore how to monetize your valuable knowledge.

Introduction

In our previous series,  https://onlycoders.net/article/90/simplified-global-state-management-and-api-requests-in-react-typescript-implementing-redux-toolkit-rtk-and-rtk-query-part-one-90, we explored the implementation of Redux for global state management in React. However, we encountered a drawback: the absence of data persistence on page or hard refresh. To address this and ensure a seamless user experience, we'll dive into implementing Redux Persist using the redux-persist package, continuing from where we left off in the previous series.


Implementation Steps

  1. Installation of Redux Persist

Begin by installing the 'redux-persist' package:

npm i redux-persist

Start the application:

npm run dev

2. Adapting the Redux Store

In the src/app/store.ts directory, modify the Redux store to incorporate redux-persist.

Snippet:

import { configureStore, combineReducers } from "@reduxjs/toolkit";
import storage from "redux-persist/lib/storage";
import {
  persistReducer,
  PersistConfig,
  FLUSH,
  REHYDRATE,
  PAUSE,
  PERSIST,
  PURGE,
  REGISTER,
} from "redux-persist";

import counterReducer from "../pages/counter/counterSlice";

// Persist configuration
const perisistConfig: PersistConfig<RootState> = {
  key: "root",
  version: 1,
  storage,

  /**
   * https://redux-toolkit.js.org/usage/usage-guide#use-with-redux-persist
   *
   * It is also strongly recommended to blacklist any api(s) that you have configured with RTK Query. If the api slice reducer is not blacklisted, the api cache will be automatically persisted and restored which could leave you with phantom subscriptions from components that do not exist any more.
   */
  // blacklist: [pokemonApi.reducerPath],
};

const rootReducer = combineReducers({
  // Key should match name of slice
  counter: counterReducer,
});

// Persist the reducers
const persistedReducer = persistReducer(perisistConfig, rootReducer);

export const store = configureStore({
  reducer: persistedReducer,
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({
      serializableCheck: {
        ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
      },
    }),
});

// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof rootReducer>;

// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch;

Here, we configure redux-persist using persistReducer and define perisistConfig. This configuration includes setting a key for storing data in the local storage and optionally blacklisting specific reducers from being persisted. Blacklisting ensures that certain data, such as API caches from RTK Query, isn't persisted unnecessarily. This is recommended by redux because If the api slice reducer is not blacklisted, the API cache will be automatically persisted and restored which could leave you with outdated subscriptions from components that do not exist anymore.

3. Combining Reducers

Employ combineReducers to structure a cleaner object for the persistReducer definition, enhancing readability and manageability.

4. Integration of Redux Persist in the Application

Integrate redux-persist into the root of your React application and wrap the app with PersistGate to manage the persistence process.  

Snippets:

import ReactDOM from "react-dom/client";
import { persistStore } from "redux-persist";
import { PersistGate } from "redux-persist/integration/react";

import App from "./App.tsx";
import { store } from "./app/store";
import "./index.css";

const persistor = persistStore(store);

ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    <Provider store={store}>
      <PersistGate persistor={persistor}>
        <App />
      </PersistGate>
    </Provider>
  </React.StrictMode>
);

Here, we import persistStore from redux-persist and use PersistGate to wrap the App component within Provider, ensuring seamless persistence of the Redux store across sessions.

Conclusion

By implementing redux-persist, we've enhanced our Redux-powered React application, ensuring data persistence and providing a smoother user experience. Stay tuned for further enhancements in the next series!

 

488 views

Please Login to create a Question