Correct setup of redux-persist v5 with react boilerplate - reactjs

I have been trying to setup redux-persist 5.9.1 with reactboilerplate 3.4.0 framework.
The error I receive seems to related to redux-immutable and I am unable to figure out right configuration.
Here is what I have done so far:
1. Install NPM
npm i -S redux-persist redux-persist-transform-immutable
package.json
"redux-persist": "^5.9.1",
"redux-persist-transform-immutable": "^5.0.0",
2. Setup Redux Persist in store.js
//store.js
import .... (other usual stuff)
import { persistStore, persistReducer } from 'redux-persist';
import storageSession from 'redux-persist/lib/storage/session';
import immutableTransform from 'redux-persist-transform-immutable';
const persistConfig = {
transforms: [immutableTransform()],
key: 'root',
storage: storageSession,
}
const rootReducers = createReducer();
// Using persistReducer not persistCombineReducer because the rootReducer is already returned by combinedReducer from redux-immutable.
const persistedReducer = persistReducer (persistConfig, rootReducers)
export default function configureStore (initialState = {}, history) {
// other usual stuffs ...
// I modified how store is created using persistedReducer
const store = createStore(
persistedReducer, // this line used to use createReducer() method
fromJS(initialState),
composeEnhancers(...enhancers),
);
const persistor = persistStore(store);
return { persistor, store };
// Please note, I have commented out hot reloading of reducers for now.
}
3. No change in reducers.js
4. Update App.js
import 'babel-polyfill';
import React from 'react';
// Added below
import { PersistGate } from 'redux-persist/es/integration/react';
// other usual setup
// Line below used to define just store but now we are defining persistor and store
const { persistor, store } = configureStore(initialState, browserHistory);
// Finally, update the render method:
const render = () => {
ReactDOM.render(
<Provider store={store}>
<PersistGate persistor={persistor}>
<Router
history={history}
routes={rootRoute}
render={
applyRouterMiddleware(useScroll())
}
/>
</PersistGate>
</Provider>,
document.getElementById('app')
);
};
And still no luck:
Error:
I think I do not have immutable maps configured right. Any help?

The way you doing is correct as documentation.
The problem is in here:
const rootReducers = createReducer();
// Using persistReducer not persistCombineReducer because the rootReducer is already returned by combinedReducer from redux-immutable.
const persistedReducer = persistReducer (persistConfig, rootReducers)
This const rootReducers = createReducer(); should not call like that, it will trigger the function. You should put like const rootReducers = createReducer; or better call like this:
const persistedReducer = persistReducer (persistConfig, createReducer)
Please see documentation, not call rootReducer for trigger function but pass it as variable.

Related

Notes app "redux-persist failed to create sync storage. falling back to noop storage."

I am using React Native to make a notes app, using redux for storage. I want this storage to persist so I am using redux-persist. However I'm getting this error: redux-persist failed to create sync storage. falling back to noop storage.
I have looked through the pervious answers but none of them seem to apply to me. Here is App.js:
import Main from "./src/components/Main"
import { NativeRouter } from "react-router-native"
import { createStore } from "redux"
import { Provider } from "react-redux"
import reducer from "./src/reducer"
import AsyncStorage from "#react-native-async-storage/async-storage"
import { persistStore, persistReducer } from "redux-persist"
import storage from "redux-persist/lib/storage"
import { PersistGate } from "redux-persist/integration/react"
import Text from "./src/components/Text"
const persistConfig = {
key: "root",
storage: AsyncStorage,
}
const persistedReducer = persistReducer(persistConfig, reducer)
const store = createStore(persistedReducer)
const persistor = persistStore(store)
export default function App() {
return (
<NativeRouter>
<Provider store={store}>
<PersistGate loading={<Text>Loading...</Text>} persistor={persistor}>
<Main />
</PersistGate>
</Provider>
</NativeRouter>
)
}

Uncaught TypeError: Cannot read properties of undefined (reading 'dispatch')

I'm currently trying to use React + Typescript + Redux and I'm running into an issue. I'm trying to test the Redux Store setup via chrome devTools. I know I butchered the code (very new to Typescript) and I'm getting this error 'Uncaught TypeError: Cannot read properties of undefined (reading 'dispatch')' every time I test it. I tried declaring a global window state, installed redux-dev-tools, but still very lost.
This is what my store/index.tsx file look like:
import {
legacy_createStore as createStore,
combineReducers,
applyMiddleware,
compose,
StoreEnhancer,
} from "redux";
import { devToolsEnhancer } from "redux-devtools-extension";
import thunk from "redux-thunk";
const rootReducer = combineReducers({});
let enhancer;
if (process.env.NODE_ENV === "production") {
enhancer = applyMiddleware(thunk);
} else {
const logger = require("redux-logger").default;
const composeEnhancers =
(window && (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) || compose;
enhancer = composeEnhancers(applyMiddleware(thunk, logger));
}
const configureStore = () => {
return createStore(rootReducer, devToolsEnhancer({}));
};
export default configureStore;
and my types/index.d.ts:
import { StoreEnhancer } from 'redux'
export {};
declare global {
interface Window {
store: {};
__REDUX_DEVTOOLS_EXTENSION__?: () => StoreEnhancer;
}
}
And finally my src/index.tsx:
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import { Provider } from "react-redux";
import { BrowserRouter } from "react-router-dom";
import configureStore from "./store";
const store = configureStore();
if (process.env.NODE_ENV !== "production") {
window.store = store;
};
function Root() {
return (
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>
);
}
const root = ReactDOM.createRoot(
document.getElementById("root") as HTMLElement
);
root.render(
<React.StrictMode>
<Root />
</React.StrictMode>
);
I will also attach screenshots of my file setup:
And my console error:
I am open to all suggestions, thank you!
The first issue here is that the store setup code is using outdated patterns and a lot of handwritten code. Today, you should be using our official Redux Toolkit package to write your Redux apps, and as part of that, RTK's configureStore API. It does all that same work with just a few lines:
import { configureStore } from "#reduxjs/toolkit";
const store = configureStore({
reducer: {
posts: postsReducer,
comments: commentsReducer
}
})
That automatically combines reducers, adds the Redux DevTools extension setup, and adds the thunk middleware.
See our docs for guidance on setup:
https://redux.js.org/tutorials/quick-start
https://redux.js.org/tutorials/typescript-quick-start
https://redux.js.org/introduction/why-rtk-is-redux-today
https://redux.js.org/tutorials/essentials/part-2-app-structure
As for the specific error message you're seeing... the code seems like it would run. My guess is that something is wrong with the process.env.NODE_ENV check you added and so it's not assigning window.store.
RTK also works much better with TypeScript than legacy Redux code does.

Using Redux-Persist with REST API

I have followed countless tutorials on redux-persist and believe I am implementing it correct in my redux-toolkit app. However, I think there's a disconnect in fundamental understanding on my end. Can I use persist on an application that uses REST API or do I need to setup my on backend server for it to work? And if you cant use persist for an app that uses REST API, how would I go about getting state to persist on an app that uses Redux-Toolkit? In Application in my browser's devtools, it shows that my state has been saved but when I close the browser window and open it back up, I find that my shopping cart is empty. Here's my code just in case I'm missing something:
Store js
import cartReducer from "./features/Cart/cartSlice"
import modalReducer from "./features/Modal/modalSlice"
//Persist
import { persistStore, persistReducer } from "redux-persist";
import storage from "redux-persist/lib/storage";
const persistConfig = {
key: "persist-key",
storage
}
const persistedReducer = persistReducer(persistConfig, cartReducer)
const store = configureStore({
reducer: {
persistedReducer: persistedReducer,
cart: cartReducer,
modal: modalReducer,
},
middleware: (getDefaultMiddleware) => getDefaultMiddleware({
serializableCheck: false
})
})
const persistor = persistStore(store)
export default store;
export { persistor }
Index js
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import store, {persistor} from "./store"
import { PersistGate } from 'redux-persist/integration/react';
import { Provider } from 'react-redux';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<Provider store={store}>
<PersistGate persistor={persistor}>
<App />
</PersistGate>
</Provider>
</React.StrictMode>
);
Any help will be appreciated.
Yes you can use redux-persist to able keep data at client side,
but keep on mind, you should never keep sensible data. And use it only keep needful data such as session data settings, etc.
You can retrieve all such as normal redux data, handler as useSelector from react-redux library will return your current state.
So your backend not implements nothing to warranty your redux flow, it is entirety responsibility of frontend.

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.

redux devtools not showing state

can anybody please tell me why is my redux app not working? I have been going step by step from tutorial from youtube but my state isn't event shown in redux dev tools. All I have there is 'states are equal'.
counter.js file (reducer)
const counterReducer = (state = 0, action) => {
switch (action.type) {
case 'INCREMENT':
return state + 1;
default:
return state;
}
}
export default counterReducer;
index.js file
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
//reducer
import counterReducer from './Reducers/counter';
//store
import {createStore} from 'redux';
//provider
import { Provider } from 'react-redux';
const store = createStore(
counterReducer,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById('root')
);
What Am I doing wrong?
try this code below in your index.js file.
import { createStore, compose } from 'redux';
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
counterReducer,
composeEnhancers()
);
and if you are using any middleware like redux-thunk, then do as following,
import { createStore, applyMiddleware, compose } from 'redux';
const store = createStore(
rootReducer,
composeEnhancers(applyMiddleware(thunk))
);
If you want to update anything inside redux store then you have to dispatch an action mandatorily. Create an action, dispatch that action from your component. Then you will see everything working.
The above rated solution is accurate, but we have some cases when we don't want the end users to see our state using React DevTools. For example, in a production environment, we don't want this to happen. To implement this functionality use this chunk of code.
import { createStore, compose } from 'redux';
// if env is not equal to 'production', show state in Redux DevTools
const composeEnhancers = (process.env.REACT_APP_NODE_ENV !== 'production' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) || compose;
const store = createStore(counterReducer,composeEnhancers());
// rest of the code goes here...
My solution was to change from "Autoselect instances" in the right upper corner to my own instance. The state was 'hidden' and that's why I couldn't see it despite configured everything correctly.

Resources