Using redux-persist only in development environment - reactjs

I'm using redux-persist and it's great.
However, when I try to use it only in development, it doesn't seem to work. What am I doing wrong here?
store.js
import thunk from 'redux-thunk';
import { createStore, applyMiddleware, compose } from 'redux';
import { persistStore, persistReducer } from 'redux-persist';
import storage from 'redux-persist/lib/storage';
import rootReducer from './reducers';
const persistConfig = {
key: 'root',
storage,
};
let store;
let persistor;
// Show the Redux Devtools only in development mode.
if (process.env.NODE_ENV === 'development') {
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const persistedReducer = persistReducer(persistConfig, rootReducer);
store = createStore(persistedReducer, composeEnhancers(applyMiddleware(thunk)));
persistor = persistStore(store);
} else {
store = createStore(rootReducer, applyMiddleware(thunk));
}
export { store, persistor };
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { PersistGate } from 'redux-persist/integration/react';
import App from './App';
import { store, persistor } from './store';
import registerServiceWorker from './registerServiceWorker';
if (process.env.NODE_ENV === 'development') {
ReactDOM.render(
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<App />
</PersistGate>
</Provider>,
document.getElementById('root'),
);
} else {
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root'),
);
}
registerServiceWorker();

I'm not sure why it's not working for you but I solved this problem by changing the whitelist/blacklist config based on whether I wanted to persist the data or not! Also, you should see about the "nested persists" to give better control": https://www.npmjs.com/package/redux-persist
When you don't want to persist the store, just add a "whitelist" attribute to your config for one inconsequential value in the store like "loading".

Related

Redux-toolkit redux-persist not work on mobile or safari desktop

I am developing a platform for which I am using react-redux-devtools and redux persist to persist the state of the application, everything is perfect, even if I access it from localhost:3000/ in safari it works perfectly. When I test it in the deploy is when the problem comes.
My App.js file is as follows:
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import { Provider } from "react-redux";
import {store} from "./app/store";
import { PersistGate } from 'redux-persist/integration/react'
import { persistStore } from 'redux-persist'
const root = ReactDOM.createRoot(document.getElementById('root'));
const persistor = persistStore(store)
root.render(
<React.StrictMode>
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<App />
</PersistGate>
</Provider>
</React.StrictMode>
);
The code of my store file
import {combineReducers, configureStore} from '#reduxjs/toolkit'
import {persistReducer} from 'redux-persist'
import thunk from "redux-thunk";
import articulosReducer from '../features/articulos/traerArticulosSlice'
import titulos_normasReducer from '../features/normas/traerNormasSlice'
import normaActivaReducer from '../features/normas/normaActivaSlice'
import articuloSeleccionadoReducer from '../features/articulos/articuloSeleccionadoSlice'
import usuarioLoginReducer from '../features/usuarios/loginUsuarioSlice'
import crearUsuarioReducer from '../features/usuarios/createUsuarioSlice'
import crearNormaSlice from '../features/normas/crearNormaSlice'
import {CookieStorage} from "redux-persist-cookie-storage";
import Cookies from 'cookies-js'
const persistConfig = {
key: 'root',
storage: new CookieStorage(Cookies, {}),
whitelist: ['titulos_normas', 'usuario']
}
const rootReducer = combineReducers({
usuario: usuarioLoginReducer,
titulos_normas: titulos_normasReducer,
articulos: articulosReducer,
normaSelected: normaActivaReducer,
articuloSeleccionado: articuloSeleccionadoReducer,
crearUsuario: crearUsuarioReducer,
crearNorma: crearNormaSlice
})
const persistedReducer = persistReducer(persistConfig, rootReducer)
export const store = configureStore({
reducer : persistedReducer,
middleware: [thunk]
})
To make redux-edvtool and persist works on mobile and safati web browser

why do my redux- persist lose data on reload?

I am using redux persist in my web application to store data in localStorage but redux lose data on page reload. does anybody have the same issue or anybody can help me with this.
my redux-persist initialization is:
import { createStore } from "redux";
import userData from "./reducers/reducers";
import { persistStore, persistReducer } from "redux-persist";
import storage from "redux-persist/lib/storage";
const persistConfig = {
key: "root",
storage,
whitelist: ["userData"],
};
const persistedReducer = persistReducer(persistConfig, userData);
const store = createStore(persistedReducer);
export const persistor = persistStore(store);
export default store;
while my index.js:
import React from "react";
import ReactDOM from "react-dom";
import "./index.scss";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import { Provider } from "react-redux";
import { PersistGate } from "redux-persist/lib/integration/react";
import { persistor } from "./redux/store";
import store from "./redux/store";
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<PersistGate persistor={persistor}>
<App />
</PersistGate>
</Provider>
</React.StrictMode>,
document.getElementById("root")
);
reportWebVitals();
I am unable to find any bug or bad practice can anyone help me.
Redux-persist will handle all the stuff. redux-persist
Example :
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 }
}
App.js
import { PersistGate } from 'redux-persist/integration/react'
const App = () => {
return (
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<RootComponent />
</PersistGate>
</Provider>
);
};
I don't see anything 'wrong' with your code, the only difference is that you dont have a rootReducer, also you dont need to put a whitelist, since when I used whitelist it didn't filter the others, at least it didn't work for me, what did work for stating which reducer should/shouldn't keep storage was using blackList and passing the reducers that wasnt working.
Try giving a shot creating a rootReducer.
I've experienced it too, make sure the data you want to persist is by calling the reducer that would put a value on the state. ex of authToken.

TypeError: Object(...) is not a function Redux Store

I got stacked with error for a while, I searched on the web all the answers I found on Stack Overflow and GitHub was related to updating React or correcting importing spelling, I did all of that but still Stacked.
Here is my Store
import { compose, createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import firebase from '../firebase/Firebase';
import { reactReduxFirebase, getFirebase } from 'react-redux-firebase';
import rootReducer from './reducers/rootReducer';
// react-redux-firebase config
const rrfConfig = {
userProfile: 'users',
useFirestoreForProfile: true, // Firestore for Profile instead of Realtime DB
attachAuthIsReady: true, // attaches auth is ready promise to store
};
const store = createStore(
rootReducer,
compose(
reactReduxFirebase(firebase, rrfConfig),
applyMiddleware(thunk.withExtraArgument({ getFirebase })),
// for redux dev tools
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
)
);
export default store;
Here is my index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import { BrowserRouter } from 'react-router-dom';
import 'react-toastify/dist/ReactToastify.css';
import { Provider } from 'react-redux';
// store
import store from '../src/redux/store';
ReactDOM.render(
// <React.StrictMode>
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>,
// </React.StrictMode>,
document.getElementById('root')
);
serviceWorker.unregister();
After a lot of research I found out the solution for this problem.
The problem is with the react-redux-firebase package, they've changed the way to initialize the package, here is the new code structure.
The Store:
import { compose, createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import firebase from '../firebase/Firebase';
import { getFirebase } from 'react-redux-firebase';
import rootReducer from './reducers/rootReducer';
// react-redux-firebase config
const rrfConfig = {
userProfile: 'users',
useFirestoreForProfile: true, // Firestore for Profile instead of Realtime DB
attachAuthIsReady: true, // attaches auth is ready promise to store
};
const store = createStore(
rootReducer,
compose(
applyMiddleware(thunk.withExtraArgument({ getFirebase })),
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
)
);
const rrfProps = {
firebase: firebase,
config: rrfConfig,
dispatch: store.dispatch,
// createFirestoreInstance // <- needed if using firestore
};
export { store, rrfProps };
Index js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import { BrowserRouter } from 'react-router-dom';
import 'react-toastify/dist/ReactToastify.css';
import { Provider } from 'react-redux';
import { ReactReduxFirebaseProvider } from 'react-redux-firebase';
// store
import { store, rrfProps } from '../src/redux/store';
ReactDOM.render(
// <React.StrictMode>
<Provider store={store}>
<ReactReduxFirebaseProvider {...rrfProps}>
<BrowserRouter>
<App />
</BrowserRouter>
</ReactReduxFirebaseProvider>
</Provider>,
// </React.StrictMode>,
document.getElementById('root')
);
serviceWorker.unregister();
This is where I found the solution react-redux-firebase

React-Router with redux-persist

After updating most packages in my react project, I can no longer figure out what changed to make redux-persist work when using connected-react-router (updated from react-redux-router which is now deprecated).
I've tried looking at guides online but none seem to integrate redux-persist with connected-react-router. How would I go about using the new connected-react-router with a setup like this?
package versions:
├── connected-react-router#6.6.0
├── react#16.12.0
├── react-redux#6.0.1
└── redux-persist#6.0.0
src/index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import './css/index.css';
import App from './components/App';
import registerServiceWorker from './registerServiceWorker';
import { PersistGate } from 'redux-persist/integration/react'
import createHistory from 'history/createBrowserHistory'
import { ConnectedRouter } from 'connected-react-router'
import { Provider } from 'react-redux'
import configureStore from './store'
const history = createHistory();
const store = configureStore(history);
ReactDOM.render((
<Provider store={store}>
<ConnectedRouter history={history}>
<App/>
</ConnectedRouter>
</Provider>
), document.getElementById('root'));
registerServiceWorker();
src/store.js:
import { applyMiddleware, createStore, compose } from 'redux'
import { createFilter } from 'redux-persist-transform-filter';
import { persistReducer, persistStore } from 'redux-persist'
import { routerMiddleware } from 'connected-react-router'
import thunk from "redux-thunk";
import storage from 'redux-persist/lib/storage'
import apiMiddleware from './middleware';
import rootReducer from './reducers'
import createRootReducer from './reducers'
export default (history) => {
const persistedFilter = createFilter(
'auth', ['access', 'refresh']
);
const reducer = persistReducer(
{
key: 'root',
storage: storage,
whitelist: ['auth', 'user', 'game'],
transforms: [ persistedFilter]
},
rootReducer
);
const store = createStore(
createRootReducer(history), {},
compose(
applyMiddleware(thunk, apiMiddleware, routerMiddleware(history)),
window.devToolsExtension ? window.devToolsExtension() : f => f,
),
);
persistStore(store);
return store;
}
src/reducers/index.js:
import { combineReducers } from 'redux'
import { connectRouter } from 'connected-react-router'
import auth, * as fromAuth from './auth'
import { reducer as form } from 'redux-form';
const createRootReducer = (history) => combineReducers({
router: connectRouter(history),
auth: auth,
// other reducer stuff
});
export default createRootReducer
One thing to check, it could have something to do with PersistGate?
In your src/index.js, you are importing PersistGate, but not using it.
import { PersistGate } from 'redux-persist/integration/react'
Try using it by wrapping your root component with PersistGate. i.e. like this.
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<ConnectedRouter history={history}>
<App/>
</ConnectedRouter>
</PersistGate>
</Provider>
To do that, you'll need access to persistor which is something you'll need to define when you call persistStore(store). i.e. some minor refactoring of your src/store.js will be required.
Further information about this is found in the doc for redux-persist. It says...
If you are using react, wrap your root component with PersistGate. This delays the rendering of your app's UI until your persisted state has been retrieved and saved to redux.

React with redux-persist when navigate the UI is stuck

When I navigate through the app the UI is stuck although the url changes.
I would like to integrate redux-persist on my current app but it eventually drove me to a strange bug to me.
Note: I use also the redux-saga as middleware on creating the store.
store.js
import { createStore, applyMiddleware, compose } 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 createSagaMiddleware from 'redux-saga'
import rootReducer from "../reducers/index";
import rootSaga from '../sagas/index'
const persistConfig = {
key: 'root',
storage,
}
const persistedReducer = persistReducer(persistConfig, rootReducer)
const sagaMiddleware = createSagaMiddleware()
const middleware = applyMiddleware(sagaMiddleware)
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
const store = createStore(
persistedReducer,
{},
composeEnhancers(middleware)
)
export const persistor = persistStore(store)
sagaMiddleware.run(rootSaga)
export default store
window.store = store
When I comment in the Persist Gate component then the navigation works as intended.
index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { BrowserRouter as Router } from "react-router-dom";
import { Provider } from 'react-redux'
import registerServiceWorker from "./js/registerServiceWorker";
import { PersistGate } from 'redux-persist/integration/react'
import store, { persistor } from './js/store';
ReactDOM.render(
<Router>
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<App />
</PersistGate>
</Provider>
</Router >,
document.getElementById("root")
);
registerServiceWorker();
I hope I made myself clear!
Try wrapping your Router with the PersistGate. The order of these higher order components matters for React Router. The way you have it now, when you change the url it's not triggering a re-render, so swapping the order should fix the issue.

Resources