React with redux-persist when navigate the UI is stuck - reactjs

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.

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.

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.

connectedRouter Error: Could not find router reducer in state tree, it must be mounted under "router"

I am new to React.js and was setting up base project at that I was getting one issue that my routing got changed but component doesn't load. After googling I found that I need to use ConnectedRouter. While setting up ConnectedRouter, I am getting console error: Could not find router reducer in state tree, it must be mounted under "router"
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import { ConnectedRouter, connectRouter, routerMiddleware } from "connected-react-router";
import { Provider } from "react-redux";
import { createStore, combineReducers, applyMiddleware, compose } from 'redux';
import createSagaMiddleware from 'redux-saga';
import loginReducer from "./store/reducers/login";
import { watchLogin} from "./store/sagas";
import { history } from '../src/shared/history';
import { push } from 'react-router-redux';
import './index.css';
import App from './App';
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const rootReducer = combineReducers({
login: loginReducer
});
const routersMiddleware = routerMiddleware(history)
const sagaMiddleware = createSagaMiddleware();
const middlewares = [sagaMiddleware, routersMiddleware];
const store = createStore(
connectRouter(history)(rootReducer),
{},
composeEnhancers(applyMiddleware(...middlewares))
);
sagaMiddleware.run(watchLogin);
const app = (
<Provider store={store}>
<ConnectedRouter history={history}>
<App />
</ConnectedRouter>
</Provider>
);
ReactDOM.render(app, document.getElementById('root'));
For the sake of helping future souls with this issue, it turns out that according to the linked github discussions, that version 5.0 of the history package is causing the issue and downgrading to version 4.10.1 solves the problem for me.
npm install history#4.10.1
https://github.com/ReactTraining/history/issues/803
https://github.com/ReactTraining/history/issues/804
Add router in your reducer with using connectRouter and history
Refer this link
https://www.npmjs.com/package/connected-react-router
import { connectRouter } from 'connected-react-router'
const rootReducer = combineReducers({
login: loginReducer,
router: connectRouter(history),
});
The main issue is the version of the history package, with react-router-dom v5 you need to use history v4 (the latest version of which is 4.10.1) - history v5 is only compatible with react-router-dom v6.
You have forgotten :
router: connectRouter(history),
in your combineReducers()
If you use immutable you should import ConnectedRouter from 'connected-react-router/immutable'.
I ran into the same issue.
I forgot to give the history as a parameter to my rootReducer, in my store initialization.
const store = createStore(
rootReducer(history), // <-- HERE
{},
...
)

Using redux-persist only in development environment

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".

Resources