Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[V5] How to purge when I want to clear the storage cache in ReactNative? #579

Closed
landpy opened this issue Nov 20, 2017 · 17 comments
Closed

Comments

@landpy
Copy link

landpy commented Nov 20, 2017

Hi rt2zz~
I want to click one button to clear the storage cache in ReactNative, I used PersistGate but I don't know how to invoke the purge method in the RN component. Could you please explain how to invoke purge method when the onPress event occurs?Thx a lot!!
The code is as following:
import * as React from 'react';
import { Provider } from 'react-redux';
import { PersistGate } from 'redux-persist/es/integration/react';

import IntlComponent from './IntlComponent';
import configureStore from './middlewares';

import {View,Text} from 'react-native';

const { persistor, store } = configureStore();
const onBeforeLift = () => {
// take some action before the gate lifts
}

export default class App extends React.Component {
render() {
return
<PersistGate
onBeforeLift={onBeforeLift}
persistor={persistor}
loading={}>



}
}

@mzafer
Copy link

mzafer commented Dec 27, 2017

Hi @landpy, did you figure this out ?

@testlump
Copy link

testlump commented Jan 4, 2018

You should be able to dispatch a PURGE action to the store and this will invoke the purgeStoredState method. Rough example below:

Reducer:

import { PURGE, REHYDRATE } from 'redux-persist';

function myReducer(state = {}, action) { 
     switch(action.type) { 
          // [....Your other reducer actions...]  
           REHYDRATE:    // This added just to show that this action type also exists, can be omitted. 
                  console.log("REHYDRATING!!!!");    
                  return state;
           PURGE: 
                  console.log("PURGING!!!!"); 
                  return {};    // Return the initial state of this reducer to 'reset' the app 
     }
}

Test Component:

import React from "react";
import { PURGE } from 'redux-persist';

// Generate <TestComponent /> with a button that will purge the persisted store
class TestComponent extends React.Component { 
      constructor(props) { 
         super(props);
      }    
    
      onPurgeStoredState(e) { 
            e.PreventDefault();
     
             const { dispatch } = this.props;   // Grab a ref to the mapped dispatch method

             // Create and dispatch the action which will cause redux-persist to purge
             dispatch({ 
                  type: PURGE,
                  key: "myStorageKey",    // Whatever you chose for the "key" value when initialising redux-persist in the **persistCombineReducers** method - e.g. "root"
                 result: () => null              // Func expected on the submitted action. 
              });        
       }

       render() { 
             return(<button onClick={this.onPurgeStoredState.bind(this)}></button>);
        }
}

function mapStateToProps(
    state,
    ownProps
) { 
    return state;
}

function mapDispatchToProps( 
    dispatch
) {
   return { dispatch };     // Map dispatch method to this.props.dispatch
}

export default connect(mapStateToProps, mapDispatchToProps)(TestComponent);

Wire in the reducer and test component into your app and you should (hopefully) find when you click the button, the store is cleared and messages are logged to the console.

@rt2zz
Copy link
Owner

rt2zz commented Feb 1, 2018

@landpy apologize for taking so long to get around to this. There are a few approaches here depending on your needs.

  1. You can use purgeStoredState to purge state. import { purgeStoredState } from 'redux-persist'
  2. You can use persistor.purge() in order to purge state. This is nice because it does not require config as an argument.
  3. if you also want to do a state reset which it sounds like is the case you can either use an existing module for that (a few exist I believe) or you can do @testlump suggestion here: implement a custom handler for PURGE which does state reset

@rt2zz rt2zz closed this as completed Feb 1, 2018
@tommyalvarez
Copy link

tommyalvarez commented Apr 4, 2018

@rt2zz i landed here accidentally after hours of google searching on why redux-persist wasn't persisting to my local storage a state change in session reducer after user was logged out. During logged out i just cleared the session to the initial state (without mutating of course), but redux-persist didn't appear to persist the newly blank values into local storage and hence... on a refresh the auto rehydrate would bring back the values as if the user was still logged in.
I can of course confirm that persisting was working because inspecting the local storage, the values were there saved. Do you know why this happens ? Version 5. I was expecting all changes on the reducer to be persisted immediately. Of course i ended up using your alternative 2 solution, but i'm curious anyway
Regards

@Kevin-Do
Copy link

Kevin-Do commented Apr 5, 2018

@tommyalvarez Hi Tommy, I'm facing the same situation as you. I'm clearing the session on log out. Did you end up just calling persistor.purge() on log out?

@tommyalvarez
Copy link

tommyalvarez commented Apr 5, 2018

@Kevin-Do Yup, that did the trick. Everything's working like a charm now. I clean the session in redux + purge, because purge will only clean the localstorage.

@Kevin-Do
Copy link

Kevin-Do commented Apr 5, 2018

@tommyalvarez Awesome, thanks!

@moahammadalt
Copy link

moahammadalt commented Aug 13, 2018

you can use this:
import { persistStore } from 'redux-persist';

and anywhere you want:
persistStore(this.props).purge();

@tommyalvarez
Copy link

tommyalvarez commented Aug 13, 2018

After more googling and checking the redux-persist documentation (on v5), i updated my project following strictly how to initiaize this library and i did not have to manually purge nothing else anymore. It's now working out of the box for me. So guideline rule: If you are manually calling purge or persist, or triggering action creators of the lib by hand... you're doing something wrong setting it up.

@bruno-edo
Copy link

bruno-edo commented Aug 13, 2018

@tommyalvarez could you provide an example showing how you're setting up everything?

Currently I'm facing the exact same issue you were having and I thought calling the persistor.purge() method was an ok alternative.

@tommyalvarez
Copy link

@bruno-edo sure, here it goes:

main.js => Where all starts in my client-side app

import React from 'react'
import ReactDOM from 'react-dom'
import createStore from './store/createStore'
import { hot } from 'react-hot-loader'
import AppContainer from './containers/AppContainer'
import { persistStore } from 'redux-persist'
// ========================================================
// Store Instantiation
// ========================================================

const initialState = window.___INITIAL_STATE__
const { history, store } = createStore(initialState) // => **Magic configuration of redux-persist happens inside here, check out below in createStore.js**

// begin periodically persisting the store
let persistor = persistStore(store)
store.persistor = persistor

// code ommited for brevity... here goes the initialization of the AppContainer with the ReactDom.render seen in every react-create-app tutorial

createStore.js:

import { applyMiddleware, compose, combineReducers, createStore } from 'redux'
import thunk from 'redux-thunk'
import { apiMiddleware } from 'redux-api-middleware'
import { createLogger } from 'redux-logger'
import makeRootReducer from './reducers'
import { routerMiddleware } from 'react-router-redux'
// I18n
import { syncTranslationWithStore, loadTranslations, setLocale } from 'react-redux-i18n'
import { translationsObject } from 'translations/index'
// Router history
import createHistory from 'history/createBrowserHistory'
// Raven for Sentry
import Raven from 'raven-js'
import createRavenMiddleware from 'raven-for-redux'
import { persistReducer } from 'redux-persist'
import storage from 'redux-persist/lib/storage'
import { createBlacklistFilter } from 'redux-persist-transform-filter'
import immutableTransform from 'redux-persist-transform-immutable'

// Do not persist unauthorized param of session state, this is custom for my project not needed
export const saveSubsetBlacklistFilter = createBlacklistFilter(
  'session',
  ['unauthorized', 'loading']
)

export const persistConfig = {
  key: 'root_key',
  storage,
  whitelist: ['session'],
  transforms: [saveSubsetBlacklistFilter, immutableTransform()], // Im using immutable in sub reducers so... need this
  debug: true
}

export default (initialState = {}) => {
// ... unrelated code ommited for brevity, middlewares and such.

// ** check makeRootReducer also! has more redux-persist config **
const persistedReducer = persistReducer(persistConfig, combineReducers(makeRootReducer()))

  // =====================================================
  // Store Instantiation and HMR Setup
  // =====================================================
  const store = createStore(
    persistedReducer,
    initialState,
    composeEnhancers(
      applyMiddleware(...middleware),
      ...enhancers
    )
  )

  store.asyncReducers = {}

  // DEPRECATED in react-router v4: To unsubscribe, invoke `store.unsubscribeHistory()` anytime
  // store.unsubscribeHistory = browserHistory.listen(updateLocation(store))

// Critical if you have react-hot-loader and webpack v4.
  if (module.hot) {
    module.hot.accept('./reducers', () => {
      const nextRootReducer = makeRootReducer(store.asyncReducers)
      store.replaceReducer(persistReducer(persistConfig, combineReducers(nextRootReducer)))
    })
  }

  syncTranslationWithStore(store)
  store.dispatch(loadTranslations(translationsObject))
  store.dispatch(setLocale('es-AR'))

  return { history, store }
}

reducers.js:

import { combineReducers } from 'redux'
import { persistReducer } from 'redux-persist'
import session from '../modules/sessions/session'
import { routerReducer } from 'react-router-redux'
import { i18nReducer } from 'react-redux-i18n'
import { reducer as toastrReducer } from 'react-redux-toastr'
import { reducer as formReducer } from 'redux-form/immutable'
import { persistConfig } from './createStore'

export const makeRootReducer = (asyncReducers) => {
  return {
    i18n: i18nReducer,
    toastr: toastrReducer,
    session,
    router: routerReducer,
    form: formReducer,
    ...asyncReducers
  }
}

// This is needed if you use reducer code split (you don't put ALL your reducers in the makeRootReducer function...). 
export const injectReducer = (store, { key, reducer }) => {
  if (Object.hasOwnProperty.call(store.asyncReducers, key)) return

  store.asyncReducers[key] = reducer
  store.replaceReducer(persistReducer(persistConfig, combineReducers(makeRootReducer(store.asyncReducers))))
  store.persistor.persist() // => **I think this is not needed anymore, i left it here when i was trying to make all this work together...**
}

Hope it helps you!

@dwjohnston
Copy link

If anyone is interested - here is Dan Abramov's solution - though it's not specific to redux-persist:

https://stackoverflow.com/questions/35622588/how-to-reset-the-state-of-a-redux-store/35641992#35641992

@namklabs
Copy link

you can use this:
import { persistStore } from 'redux-persist';

and anywhere you want:
persistStore(this.props).purge();

I'm using this before my app is rendered for debugging purposes. If something gets messed up in my localStorage, I can reset it by visiting /?debug

if( window.location.search === '?debug' ){
    persistor.purge();
}
render(
    <Provider store={store}>
	    <PersistGate loading={null} persistor={persistor}>
		    <Router history={history}>
			    <App/>
		    </Router>
	    </PersistGate>
    </Provider>,
    document.getElementById('root')
);

@fatemasagar
Copy link

@tommyalvarez could you provide an example showing how you're setting up everything?

Currently I'm facing the exact same issue you were having and I thought calling the persistor.purge() method was an ok alternative.

from where did u import persistor and purge??

@goranefbl
Copy link

goranefbl commented Jan 16, 2021

@tommyalvarez could you provide an example showing how you're setting up everything?
Currently I'm facing the exact same issue you were having and I thought calling the persistor.purge() method was an ok alternative.

from where did u import persistor and purge??

persistor is returned from persistStore.

So example:

import { persistStore } from 'redux-persist';

export const store = createStore(rootReducer, initialState, composeWithDevTools(applyMiddleware(thunk)));

export const persistor = persistStore(store);

persistor.purge();

@kirenpillay
Copy link

Why isn't this documented better and easier to find? It is very difficult to find this specific solution of calling purge() and I'm sure its a common requirement for developers?

@hyungmok
Copy link

hyungmok commented Nov 5, 2022

Thanks so much!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests