Simranjit Gill
Simranjit Gill

Reputation: 11

How to write localStorage in a Redux app using middleware?

I am creating an app which fetches the list of cities entered by a user and their respective weather using openweather API. I want the cities, as a result, to remain after I refresh the page. I know how to persist the data using browser localStorage API. But I don't know how to persist it through a middleware and pass it to the provider.

Below is my main Index.js file-:

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import ReduxPromise from 'redux-promise';

import App from './components/app';
import reducers from './reducers';
import {loadState,saveState} from './localStorage';

const persistedState=loadState();
const store=createStore(persistedState);

store.subscribe(()=>{
store.getState()
});

const createStoreWithMiddleware =
     applyMiddleware(ReduxPromise)(createStore);

ReactDOM.render(
<Provider store={createStoreWithMiddleware(reducers)}>
<App />
</Provider>
, document.querySelector('.container-fluid'));

This is the localStorage.js file-:

export const loadState=()=>{
try{
    const serializedState=localStorage.getItem('state');
    if(serializedState===null){
        return undefined;
    }
    return JSON.parse(serializedState);
}catch(err){
    return undefined;
}
};

export const saveState=(state)=>{
try {
    const serializedState=JSON.stringify(state);
    localStorage.setItem('state',serializedState);
}catch(err){
    console.log(err);
}};

I have written the reducer in different files in reducers folder.

reducers/index.js -:

import { combineReducers } from 'redux';
import WeatherReducer from './reducer_weather';

const rootReducer = combineReducers({
weather:WeatherReducer
});

export default rootReducer;

and another reducer in reducers/reducer_weather.js -:

import {FETCH_WEATHER} from '../actions/index';
import {DELETECITY} from '../actions/deleterow';
export default function(state=[],action){

switch(action.type){
    case FETCH_WEATHER:
        console.log([action.payload.data, ...state]);
        return [action.payload.data, ...state];
    case DELETECITY:
        console.log([...state].filter((weather)=>{
            return weather.city.id!==action.payload
        }));
        return [...state].filter((weather)=>{
            return weather.city.id!==action.payload
        });
    default:
        return state;

    }; 
}

Before using the localStorage for persisting the application state, my code was working fine. But now it is showing me an error. I am facing a problem regarding const createStoreWithMiddleware = applyMiddleware(ReduxPromise)(createStore);

how to use store using this middleware and how to pass in <Provider> tag's store property?

Upvotes: 1

Views: 5403

Answers (1)

Jordan Enev
Jordan Enev

Reputation: 18664

I would suggest you to use redux-persist.

Persist and rehydrate a redux store

Using this middleware all the data you have in the Redux Store will be automatically persisted to the localStorage (different type of storage can be used too). Therefore, when you refresh a page, the already persisted data from the previous request will be automatically rehydrated (pushed) back to the Store.


Example, taken from documentation:

Configuration:

// configureStore.js

import { createStore } from 'redux'
import { persistStore, persistReducer } from 'redux-persist'
import storage from 'redux-persist/lib/storage' // defaults to localStorage for web and AsyncStorage for react-native

import rootReducer from './reducers'

const persistConfig = {
  key: 'root',
  storage,
}

const persistedReducer = persistReducer(persistConfig, rootReducer)

export default () => {
  let store = createStore(persistedReducer)
  let persistor = persistStore(store)
  return { store, persistor }
}

Usage:

import { PersistGate } from 'redux-persist/integration/react'

// ... normal setup, create store and persistor, import components etc.

const App = () => {
  return (
    <Provider store={store}>
      <PersistGate loading={null} persistor={persistor}>
        <RootComponent />
      </PersistGate>
    </Provider>
  );
};

Upvotes: 2

Related Questions