I am using redux persist to store my redux state in local storage. The redux persist is working to store data in localstorage, but when I reload the page the data is gone from local storage and state. Here is link of the repo of project on which I am working https://github.com/bakarfreelancer/jccs-frontend. And The below is my reducer and store Index file.
//Reducer/Index.js
import { configureStore } from "#reduxjs/toolkit";
import { combineReducers, compose } from "redux";
import storage from "redux-persist/lib/storage";
import {
persistReducer,
FLUSH,
REHYDRATE,
PAUSE,
PERSIST,
PURGE,
REGISTER,
} from "redux-persist";
import thunk from "redux-thunk";
import usersReducer from "./usersReducer";
const persistConfig = {
key: "persistroot",
version: 1,
storage,
};
const rootReducer = combineReducers({ users: usersReducer });
const persistedReducer = persistReducer(persistConfig, rootReducer);
const store = configureStore({
reducer: persistedReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: {
ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
},
}),
});
export default store;
//
//
//
//Index.js
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import "bootstrap/dist/css/bootstrap.css";
import { Provider } from "react-redux";
import { BrowserRouter } from "react-router-dom";
import { persistStore } from "redux-persist";
import { PersistGate } from "redux-persist/integration/react";
import store from "./reducers";
let persistor = persistStore(store);
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<Provider store={store}>
<PersistGate persistor={persistor}>
<BrowserRouter>
<App />
</BrowserRouter>
</PersistGate>
</Provider>
</React.StrictMode>
);
reportWebVitals();
I want to store the redux state (which is updated after user login) in localstorage or some other storage like cookies. I checked the official documentation and I think my code is same.
The problem is solved by using redux toolkit documentation.
So by implementing the createSlice method for creating my reducers it works perfectly.
Related
Here is my code:
store.js
import {createStore, applyMiddleware, compose} from 'redux';
import {fromJS} from 'immutable';
import {routerMiddleware} from 'react-router-redux';
import createSagaMiddleware from 'redux-saga';
import createReducer from './reducers';
const sagaMiddleware = createSagaMiddleware();
export default function configureStore(initialState = {}, history) {
// Create the store with two middlewares
// 1. sagaMiddleware: Makes redux-sagas work
// 2. routerMiddleware: Syncs the location/URL path to the state
const middlewares = [sagaMiddleware, routerMiddleware(history)];
const enhancers = [applyMiddleware(...middlewares)];
const store = createStore(createReducer, fromJS(initialState), enhancers);
// Extensions
store.runSaga = sagaMiddleware.run;
store.asyncReducers = {}; // Async reducer registry
return store;
}
Routes.js
import React from 'react';
import {Route, Router, IndexRoute, browserHistory} from 'react-router';
import {syncHistoryWithStore} from 'react-router-redux';
import store from './store';
import Welcome from './containers/Welcome';
const history = syncHistoryWithStore(browserHistory, store);
const routes = (
<Router history={history}>
<Route path="/">
<IndexRoute component={Welcome} />
</Route>
</Router>
);
export default routes;
Index.js
import React from 'react';
import ReactDOM from 'react-dom';
import {browserHistory} from 'react-router';
import { Providers } from 'react-redux';
import configureStore from './store';
import routes from './routes';
const initialState = {};
const store = configureStore(initialState, browserHistory);
ReactDOM.render(
<Provider store={store}>
{routes}
</Provider>, document.getElementById('main-content')
);
I can't find where the culprit is. I tried to debug it, but can't found what really make it those error. error: Uncaught TypeError: store.getState is not a function
Any solution?
This is a typo that generated the error: TypeError: store.getState is not a function
Wrong
const store = createStore(()=>[], {}, applyMiddleware);
Correct
const store = createStore(()=>[], {}, applyMiddleware());
Notice the added parenthesis () on applyMiddleware.
in my case i got this error because my store was as shown below which is a function:
const store = preloadedState => {
let initialState={}
//some code to modify intialState
return createStore(reducer, initialState)
}
but in index.js i was passing store as a function and not the value it was returning.
wrong
<Provider store={store}>
<MyApp />
</Provider>
correct
<Provider store={store()}>
<MyApp />
</Provider>
Notice that in your Routes.js the store is not being initialized properly. You should add these lines:
const initialState = {};
const store = configureStore(initialState, browserHistory);
as in your index.js file.
I was doing this (a dynamic require) ..
const store = require('../store/app')
state = store.getState()
but for some reason when using require instead of import you have to do this ..
const store = require('../store/app')
state = store.default.getState()
Not sure if this will help but you named your import { Providers } instead of { Provider } from react-redux library.
In index.js we have to provide store() method as props value instead of store.
<Provider store={store()}>
{routes}
</Provider>
Updated index.js file.
import React from 'react';
import ReactDOM from 'react-dom';
import {browserHistory} from 'react-router';
import { Providers } from 'react-redux';
import configureStore from './store';
import routes from './routes';
const initialState = {};
const store = configureStore(initialState, browserHistory);
ReactDOM.render(
<Provider store={store()}>
{routes}
</Provider>, document.getElementById('main-content')
);
this is the solution, good luck 🤞
import { applyMiddleware, combineReducers, createStore } from "redux";
import { composeWithDevTools } from "redux-devtools-extension";
import thunk from 'redux-thunk'
const reducer = combineReducers({
products: []
})
const middleware = [thunk]
const store = createStore(
reducer,
composeWithDevTools(applyMiddleware(...middleware))
)
export default store
TypeError: store.getState is not a function -This error often occurs when you are not properly initializing middleware function. What you need to do is as below
You need to add paranthesis on applyMiddleware ( ) function and then it will behave as you are expecting it to do.
const store = createStore(()=>[], {}, applyMiddleware());
Replacing store with store() worked for me. Written below:
<Provider store={store()}>
{routes}
</Provider>
I'm trying to implement switch case for my products in Redux. I'm importing the cases from a file named productConstants using multiple export defaults. Problem is, the moment I write multiple lines, my screen turns red with this error 'A module cannot have multiple default exports.ts(2528)'
productReducers.js file
ALL_PRODUCTS_REQUEST,
ALL_PRODUCTS_SUCCESS,
ALL_PRODUCTS_FAIL} from '../constants/productConstants'
export const productsReducer = (state ={ products: [] }, action => {
switch(action.type) {
default:
return state;
}
})
my productConstants.js file
```export default ALL_PRODUCTS_REQUEST = 'ALL_PRODUCT_REQUEST'
export default ALL_PRODUCTS_SUCCESS = 'ALL_PRODUCT_SUCCESS'
export default ALL_PRODUCTS_FAIL = 'ALL_PRODUCT_FAIL'
export default CLEAR_ERRORS = 'CLEAR_ERRORS'
here is my store.js file
```//import { configureStore } from '#reduxjs/toolkit'
import { createStore, combineReducers, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import { composeWithDevTools } from 'redux-devtools-extension'
const reducer = combineReducers({
})
let initialState = {}
const middleware = [thunk];
const store = createStore( reducer, initialState, composeWithDevTools(applyMiddleware(...middleware)))
export default store;
and finally, my index.js file
```import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { Provider } from 'react-redux'
import store from './store'
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
How do I do away with this error? A module cannot have multiple default exports.ts(2528)
productConstants.js(1, 1): The first export default is here.
A module can have only one default export per module, meaning that in one JS file only one variable (or function) can be exported with the default keyword.
You can convert them all to named export:
export const ALL_PRODUCTS_FAIL = 'ALL_PRODUCT_FAIL'
I am migrating a vite and react project to Nextjs. This project uses redux-persist.
When migrating and running code it shows this error.
I was trying several solutions found on the net but none helped.
I created a new NextJS project from scratch and ended with the same error.
import { FLUSH, PAUSE, PERSIST, PURGE, REHYDRATE, DEFAULT_VERSION } from './constants';
SyntaxError: Cannot use import statement outside a module
My _app.tsx code
import { persistor, store } from "app/store";
import { Provider } from "react-redux";
function MyApp({ Component, pageProps }: AppProps) {
return (
<Provider store={store}>
<Component {...pageProps} />
</Provider>
);
}
export default MyApp;
app/store.ts
import { configureStore, combineReducers } from "#reduxjs/toolkit";
import {
persistStore,
persistReducer,
FLUSH,
REHYDRATE,
PAUSE,
PERSIST,
PURGE,
REGISTER,
} from "redux-persist";
import storage from "redux-persist/lib/storage";
import logger from "redux-logger";
import rootReducers from "./rootReducers";
const isDev = process.env.NODE_ENV === "development";
const persistConfig = {
key: "root",
version: 1,
storage,
whitelist: ["darkmode"],
};
const rootReducer = combineReducers(rootReducers);
const persistedReducer = persistReducer(persistConfig, rootReducer);
const middlewareLogger: any = !!isDev ? logger : [];
export const store = configureStore({
reducer: persistedReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: {
ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
},
}).concat(middlewareLogger),
});
export let persistor = persistStore(store);
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
Someone got it to work with NextJS?
Thanks!
I was working with redux-saga but I'm with a problem: the redux-auth-wrapper needs the redux-thunk to do the redirects, so I simply added the thunk in my store:
import {createStore, compose, applyMiddleware} from 'redux';
import createLogger from 'redux-logger';
import {routerMiddleware} from 'react-router-redux';
import {browserHistory} from 'react-router';
import thunk from 'redux-thunk';
import createSagaMiddleware, {END} from 'redux-saga';
import sagas from '../sagas';
import reduxImmutableStateInvariant from 'redux-immutable-state-invariant';
import rootReducer from '../reducers';
import _ from 'lodash';
import {loadState, saveState} from '../connectivity/localStorage';
const persistedState = loadState();
const routerMw = routerMiddleware(browserHistory);
const loggerMiddleware = createLogger();
const sagaMiddleware = createSagaMiddleware();
function configureStoreProd() {
const middlewares = [
// Add other middleware on this line...
routerMw,
sagaMiddleware,
thunk
];
const store = createStore(rootReducer, persistedState, compose(
applyMiddleware(...middlewares)
)
);
store.subscribe(_.throttle(() => {
saveState({
auth: store.getState().auth
});
}, 1000));
sagaMiddleware.run(sagas);
store.close = () => store.dispatch(END);
return store;
}
function configureStoreDev() {
const middlewares = [
// Add other middleware on this line...
// Redux middleware that spits an error on you when you try to mutate your state either inside a dispatch or between dispatches.
reduxImmutableStateInvariant(),
routerMw,
sagaMiddleware,
loggerMiddleware,
thunk
];
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; // add support for Redux dev tools
const store = createStore(rootReducer, persistedState, composeEnhancers(
applyMiddleware(...middlewares)
)
);
store.subscribe(_.throttle(() => {
saveState({
auth: store.getState().auth
});
}, 1000));
if (module.hot) {
// Enable Webpack hot module replacement for reducers
module.hot.accept('../reducers', () => {
const nextReducer = require('../reducers').default; // eslint-disable-line global-require
store.replaceReducer(nextReducer);
});
}
sagaMiddleware.run(sagas);
store.close = () => store.dispatch(END);
return store;
}
const configureStore = process.env.NODE_ENV === 'production' ? configureStoreProd : configureStoreDev;
export default configureStore;
This way works nice without errors, but I'm new in react and I don't know if have problem with redux-saga and redux-thunk working together...
Someone can help me?
No problems to have both. Sagas are just background checkers who react to some actions while thunk let's you have more interesting action creators.
While thunk will act more like synced code, sagas will do it's job in a background.
Both extensions do not change how actions are flying around. Actions still, in the end, are just bare objects like w/o thunk or w/o sagas.
Yes, of course you can use both redux-saga and redux-thunk in this way,
import { createStore, applyMiddleware } from 'redux'
import createSagaMiddleware from 'redux-saga'
import thunk from 'redux-thunk'
import logger from 'redux-logger'
import rootSagas from './sagas'
import rootReducer from './reducers'
const saga = createSagaMiddleware()
const middleWares = [saga, thunk]
export const store = createStore(
rootReducer,
applyMiddleware(...middleWares)
)
saga.run(rootSagas)
It seems there is an issue using the encrypt option of redux-persist in react-native:
https://github.com/maxdeviant/redux-persist-transform-encrypt/issues/15
Can anyone help with any solution/workaround to use redux persist to encrypt and store a login token in react-native?
When I try to use the redux persist with the redux-persist-transform-encrypt i get
Redux-persist-transform-encrypt: expected outbound state to be a string error
import { createStore, compose, applyMiddleware } from 'redux';
import ReduxThunk from 'redux-thunk';
import { persistStore, autoRehydrate } from 'redux-persist';
import { AsyncStorage } from 'react-native';
import createEncryptor from 'redux-persist-transform-encrypt';
import reducers from './reducers';
const store = createStore(
reducers,
{},
compose(
applyMiddleware(ReduxThunk),
autoRehydrate(),
),
);
const encryptor = createEncryptor({
secretKey: 'my-super-secret-key-999',
});
persistStore(
store,
{
storage: AsyncStorage,
whitelist: ['auth'],
transforms: [encryptor],
},
);
export default store;
My auth state is something like this:
const INITIAL_STATE = {
user: null,
token: ''
};
Is there any solution to use redux-persist-transform encrypt or the transform and other package to encrypt the token when using redux persist?
I found a solution using the customTransform instead of redux-persist-transform-encrypt:
import { createStore, compose, applyMiddleware } from 'redux';
import ReduxThunk from 'redux-thunk';
import { persistStore, createTransform, autoRehydrate } from 'redux-persist';
import { AsyncStorage } from 'react-native';
import CryptoJS from 'crypto-js';
import reducers from './reducers';
const store = createStore(
reducers,
{},
compose(
applyMiddleware(ReduxThunk),
autoRehydrate(),
),
);
const encrypt = createTransform(
(inboundState, key) => {
if (!inboundState) return inboundState;
const cryptedText = CryptoJS.AES.encrypt(JSON.stringify(inboundState), 'secret key 123');
return cryptedText.toString();
},
(outboundState, key) => {
if (!outboundState) return outboundState;
const bytes = CryptoJS.AES.decrypt(outboundState, 'secret key 123');
const decrypted = bytes.toString(CryptoJS.enc.Utf8);
return JSON.parse(decrypted);
},
);
persistStore(
store,
{
storage: AsyncStorage,
whitelist: ['auth'], // <-- keys from state that should be persisted
transforms: [encrypt],
},
);
export default store;
When using redux-persist initial state is triggered before rehydrating is finished so I had to apply this too:
https://github.com/rt2zz/redux-persist/blob/master/docs/recipes.md#delay-render-until-rehydration-complete
This worked for me:
import { createStore } from 'redux';
import { persistStore, persistReducer } from 'redux-persist';
import createEncryptor from 'redux-persist-transform-encrypt';
import storage from 'redux-persist/lib/storage';
import rootReducer from '/path/to/your/rootReducer';
const encryptor = createEncryptor({
secretKey: 'omg-this-is-some-secret-stuff',
});
const persistConfig = {
key: 'root',
storage,
transforms: [encryptor],
};
const reducer = persistReducer(persistConfig, rootReducer);
export const store = createStore(reducer);
export const persistor = persistStore(store);
This is working fine and store data in session storage.
Use below to encript redux data.
1) install redux-persist-transform-encrypt module
yarn add redux-persist-transform-encrypt
npm install redux-persist-transform-encrypt --save
2) import redux files.
import { createStore } from 'redux';
import { persistStore, persistReducer } from 'redux-persist';
import createEncryptor from 'redux-persist-transform-encrypt';
import storageSession from 'redux-persist/lib/storage/session';// store data in session storage
// import storage from 'redux-persist/lib/storage'; // store data in local storage
import promise from 'redux-promise';
import rootReducer from './path/reducers/';
const encryptor = createEncryptor({
secretKey: 'test#key12',
});
const persistConfig = {
key: 'root',
storage:storageSession,
// storage:storage,
transforms: [encryptor],
}
const persistedReducer = persistReducer(persistConfig, rootReducer)
export default () => {
let store = createStore(persistedReducer)
let persistor = persistStore(store)
return { store, persistor }
}