I am trying to add persistence to my redux stores, I am using Immutable.js within my webapp. I have seen the following libraries: https://github.com/rt2zz/redux-persist and https://github.com/rt2zz/redux-persist-immutable I am wondering exactly how to create the persister and the store in context of my application, please see the following config-store.js:
import rootReducer from '../reducers'
import {
createStore,
compose,
applyMiddleware
} from 'redux'
import thunk from 'redux-thunk'
export default (initialState) => {
return createStore(
rootReducer,
initialState,
compose(
applyMiddleware(thunk),
window.devToolsExtension ? window.devToolsExtension() : f => f
)
);
};
and my index.js:
import React from 'react';
import {render} from 'react-dom';
import './index.css';
import App from './App';
import {Provider} from 'react-redux';
import configureStore from './store/configure-store';
import registerServiceWorker from './registerServiceWorker';
const store = configureStore();
render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
registerServiceWorker();
Load the persiting state from local storage.
if (localStorage.getItem("state")) {
var serializedState = localStorage.getItem("state");
/* upload changes to server here */
preloadedState = JSON.parse(serializedState);
}
Save store changes to local storage.
store.subscribe(() => {
var serializedState = JSON.stringify(store.getState());
localStorage.setItem("state", serializedState);
});
Related
createStore is #deprecated so im trying to replace with configurationStore, i think the post data from my cluster is not showing because of that
```
import React from 'react';
import ReactDom from 'react-dom/client';
import { Provider } from 'react-redux';
import {createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import reducers from "./reducers";
import App from './App'
const store = createStore(reducers, (compose(applyMiddleware(thunk))))
const root = ReactDom.createRoot(document.getElementById("root"));
root.render(
<Provider store={store}>
<App />
</Provider>
);
And im trying to do it like this:
import React from 'react';
import ReactDom from 'react-dom/client';
import { Provider } from 'react-redux';
import { applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import { configureStore } from '#reduxjs/toolkit'
import reducers from "./reducers";
import App from './App'
const store = configureStore(reducers, (compose(applyMiddleware(thunk))))
const root = ReactDom.createRoot(document.getElementById("root"));
root.render(
<Provider store={store}>
<App />
</Provider>
);
```
Of Course it didn't work i'm trying to figure out how it could be
You would do
const store = configureStore({ reducer: reducers })
The thunk middleware is active automatically. compose and applyMiddleware are not needed any more. So is combineReducers.
If you had
const reducers = combineReducers({
a: reducerA,
b: reducerB
})
you could also just instead do
const store = configureStore({
reducer: {
a: reducerA,
b: reducerB
}
})
If you were still using createStore, that means that you were generally using an outdated style of Redux that is about 4x times the code of modern Redux.
Modern Redux does not use switch..case reducer, ACTION_TYPE constants, immutable reducer logic, hand-written action creators or connect & mapStateToProps. You might have been misled by an outdated tutorial.
I would highly recommend you to follow the official Redux tutorial which will leave you with knowledge of modern Redux and in the end much cleaner and easy to maintain code.
As the title says, I'm mapping through an array I have from an api in UserCardList component and it works fine but once I wrap App with PersistGate, it gives me "TypeError: users.map is not a function" and the error message from redux logger is "redux-persist: persist timed out for persist key "root". I really don't know what I'm doing wrong.
Any help would be highly appreciated.
index.js
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
import { Provider } from "react-redux";
import { PersistGate } from "redux-persist/integration/react";
import { store, persistor } from "./redux/store";
import "./index.css";
import "tachyons";
import App from "./containers/App";
ReactDOM.render(
<Provider store={store}>
<BrowserRouter>
<PersistGate persistor={persistor}>
<App />
</PersistGate>
</BrowserRouter>
</Provider>,
document.getElementById("root")
redux store
import { createStore, applyMiddleware } from "redux";
import { persistStore } from "redux-persist";
import thunkMiddleware from "redux-thunk";
import { createLogger } from "redux-logger";
import rootReducer from "../redux/root-reducer";
const logger = createLogger();
const middlewares = [logger, thunkMiddleware];
export const store = createStore(rootReducer, applyMiddleware(...middlewares));
export const persistor = persistStore(store);
export default { store, persistor };
root-reducer
import { combineReducers } from "redux";
import { persistReducer } from "redux-persist";
import storage from "redux-persist/lib/storage";
import requestUsers from "./reducers";
const persistConfig = {
key: "root",
storage,
whitelist: ["users"],
};
const rootReducer = combineReducers({
users: requestUsers,
});
export default persistReducer(persistConfig, rootReducer);
UserCardList component
import React, { Fragment } from "react";
import UserCard from "./UserCard";
const UserCardList = ({ users }) => {
return (
<Fragment>
<h1 className="f1"> Users </h1>
{users.map((user) => {
return (
<UserCard
key={user.login.uuid}
image={user.picture.large}
firstName={user.name.first}
lastName={user.name.last}
email={user.email}
city={user.location.city}
country={user.location.country}
/>
);
})}
</Fragment>
);
};
export default UserCardList;
I have created a sample project here by taking the code from your question and everything looks fine for me. And the store is getting created and users is coming as expected.
There could be a possible error in the reducers which is not posted here. Please have a look at the sample project, hope it helps.
I see in redux store you have this:
export const store = createStore(rootReducer, applyMiddleware(...middlewares));
export const persistor = persistStore(store);
// you dont need line below, you exported store and persistore in lines above
export default { store, persistor };
In my case, adding timeout: null to the persist configuration solved my issue.
const persistConfig = {
key: 'keyOfStore',
storage: storage,
// There is an issue in the source code of redux-persist (default setTimeout does not cleaning)
timeout: null,
}
const appReducer = combineReducers({
...otherReducers,
keyOfStore: persistReducer(persistConfig, keyOfStoreRedfucer),
})
Got the solution from here
I am trying to build a Trello clone using React and Redux.
Details of the application:
The application consists of 4 columns called TODO, DOING, DONE and REJECTED
I can add card to any of the 4 columns.
In the card I have just plain text.
The cards can be further moved into any of the columns using a package called react-beautiful-dnd.
There is also a delete button sticked to each card to delete the card which is added.
What I am trying to do?
I have a sample data which is first rendered when the application is first loaded.
The data is just demo, and contains id, text property for each and every card.
I want to use localstorage to add the card and further delete the card.
I want to use possibly Redux subscribe to achieve this.
I do not have much experience in dealing with Redux and localstorage altogether.
How can I do this?
Any help would be really appreciated and much required.
I have my codesandbox where I have my application running. Please consider checking out to help me out.
https://codesandbox.io/s/small-violet-zmbtf
You have to use redux persist
// configureStore.js
import { createStore } from 'redux'
import { persistStore, persistReducer } from 'redux-persist'
import storage from 'redux-persist/lib/storage' // defaults to localStorage for web
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'
// ... normal setup, create store and persistor, import components etc.
const App = () => {
return (
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<RootComponent />
</PersistGate>
</Provider>
);
};
Edited check below:
change codesandbox to:
store/index.js:
// store/index.js:
import { createStore } from "redux";
import { persistStore } from "redux-persist";
import rootReducer from "../reducers";
export const store = createStore(rootReducer);
export const persistor = persistStore(store);
*******
reducers/index.js:
// reducers/index.js:
import { combineReducers } from "redux";
import { persistReducer } from "redux-persist";
import storage from "redux-persist/lib/storage";
import listReducers from "./listReducers";
const persistConfig = {
key: "root",
storage,
whitelist: ["lists"]
};
export default persistReducer(persistConfig, combineReducers({
lists: listReducers
}));
root project index.js:
// index.js:
import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import { PersistGate } from "redux-persist/integration/react";
import { store, persistor } from "./store";
import "./styles/main.scss";
import App from "./components/App";
import * as serviceWorker from "./serviceWorker";
ReactDOM.render(
<Provider store={store}>
<PersistGate persistor={persistor}>
<App />
</PersistGate>
</Provider>,
document.getElementById("root")
);
serviceWorker.unregister();
I'm using redux-persist and I'm trying to render a screen passing it to the loading prop of PersistGate.
I did some research and I found that I should dispatch REHYDRATE to the reducer but that doesn't work either.
Maybe I'm not configuring my reducers well?
I would also like to be able to set the loading prop to null to avoid the flash screen before the App renders, but the result is the same as passing it a component to render.
This is my code of index.js
import App from './App';
import React from 'react';
import { Provider } from 'react-redux';
import { AppRegistry } from 'react-native';
import { PersistGate } from 'redux-persist/integration/react';
import { SplashScreen } from './src/screens/SplashScreen';
import configureStore from './src/store/configureStore';
const store = configureStore();
const persistor = configureStore();
const RNRedux = () => (
<Provider store={store}>
<PersistGate loading={<SplashScreen/>} persistor={persistor}>
<App />
</PersistGate>
</Provider>
);
componentDidMount = () => {
this.persistor.dispatch({ type: REHYDRATE });
};
AppRegistry.registerComponent('Sharryapp', () => RNRedux);
And that's my configureStore file:
import { createStore, combineReducers, applyMiddleware} from 'redux';
import ServerReducer from './reducers/ServerReducer';
import InviteReducer from './reducers/InviteReducer';
import { persistStore, persistReducer } from 'redux-persist';
import thunk from 'redux-thunk';
import storage from 'redux-persist/lib/storage';
const rootReducer = combineReducers({
server: ServerReducer,
invite: InviteReducer,
});
const persistConfig = {
key: 'root',
debug: true,
storage,
}
const persistedReducer = persistReducer(persistConfig, rootReducer);
const store = createStore(persistedReducer,applyMiddleware(thunk));
const persistor = persistStore(store);
export default configureStore = () => {
return ( store, persistor );
};
I am not sure why you wrap your store and persistor in a configureStore function.
Instead import both separately:
export const store = createStore(persistedReducer,applyMiddleware(thunk));
export const persistor = persistStore(store);
And import them in your desired file:
import {store, persistor} from './src/store/configureStore';
I have also noticed that your createStore call is false, since enhancers are passed as the third parameter. Change it to:
const store = createStore(persistedReducer, undefined, applyMiddleware(thunk));
That should do it.
Also you do not need to dispatch a rehydrate action as it happens automatically on app start.
I just started to use Redux Persist, and for some reason I can't get it to work.
(Cannot read property 'subscribe' of undefined error)
Persistor.js
import { createStore } from 'redux'
import { persistStore, persistReducer } from 'redux-persist'
import store from 'redux-persist/es/storage/session' // defaults to
localStorage for web and AsyncStorage for react-native
import rootReducer from './reducers'
const persistConfig = {
key: 'root',
storage: store,
}
const persistedReducer = persistReducer(persistConfig, rootReducer)
export default () => {
let store = createStore(persistedReducer)
let persistor = persistStore(store)
return { store: store, persistor: persistor }
}
index.js
import React from 'react';
import App from './components/App/App';
// import registerServiceWorker from './registerServiceWorker';
import { render } from 'react-dom'
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import { PersistGate } from 'redux-persist/integration/react'
import persistor from './Persistor'
import rootReducer from './reducers'
import 'bootstrap/dist/css/bootstrap.min.css'
import './index.css'
render(
<Provider store={persistor.persistor}>
<PersistGate loading={null} persistor={persistor.store}>
<App />
</PersistGate>
</Provider>,
document.getElementById('root')
)
with normal Redux its worked properly. But as soon I tried to switch Persist Redux I got the error I write above.
The persistor value you are importing in index isn’t an object. It is a function that returns an object containing store and the persistor.
Instantiate the persistor function and then also swap your values assigned to store in Provider with persistor in persistgate.
Rename your import to something like configureStore to prevent any conflict.
const { store, persistor } = configureStore()
render(
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<App />
</PersistGate>
</Provider>,
document.getElementById('root')
)