I am learning redux and wanted to know how can I save the state locally so when I refresh after making some changes to state it remains. I came to know about redux-persist and saw the github doc describing how to use it but its not very clear to me.
Here is the index.js code of my app -
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import App from './components/app';
import reducers from './reducers';
const createStoreWithMiddleware = applyMiddleware()(createStore);
ReactDOM.render(
<Provider store={createStoreWithMiddleware(reducers)}>
<App />
</Provider>
, document.querySelector('#container'));
How can I achieve it ?
//In your createStore have this code
import { applyMiddleware, compose, createStore } from 'redux'
import thunkMiddleware from 'redux-thunk';
import { createLogger } from 'redux-logger';
import rootReducer from '../reducers';
import { persistReducer } from 'redux-persist'
import localForage from 'localforage';
const loggerMiddleware = createLogger();
export default (initialState = {}) => {
// ======================================================
// Middleware Configuration
// ======================================================
const middleware = [thunkMiddleware, loggerMiddleware]
// ======================================================
// Store Enhancers
// ======================================================
const enhancers = []
const __DEV__ = process.env.NODE_ENV !== 'production';
if (__DEV__) {
const devToolsExtension = window.devToolsExtension
if (typeof devToolsExtension === 'function') {
enhancers.push(devToolsExtension())
}
}
// ======================================================
// Store Instantiation and HMR Setup
// ======================================================
let config = {
key: 'root',
storage: localForage,
whitelist: ['user'],
debug: __DEV__
}
let configureReducer = persistReducer(config, rootReducer)
const store = createStore(
configureReducer,
initialState,
compose(
applyMiddleware(...middleware),
...enhancers
),
)
return store
}
// In your App.js or root app, do this in your componentDidMount
persistStore(
store,
undefined,
() => {
console.log('callback::')
}
)
Here is what you should do for creating your store, using redux-persist in store.js:
import { createStore, applyMiddleware, compose, combineReducers } from 'redux';
import { persistStore, autoRehydrate } from 'redux-persist';
import localForage from 'localforage';
import { routerReducer } from 'react-router-redux';
import reducers from './container/reducers';
import middlewares from './middlewares';
const reducer = combineReducers({
...reducers,
routing: routerReducer,
});
export const initStore = (state) => {
const store = createStore(
reducer,
{},
compose(
applyMiddleware(...middlewares),
autoRehydrate(),
),
);
persistStore(store, {
storage: localForage,
whitelist: ['login'],
});
return store;
};
In your app.js, create your store this way:
import React from 'react';
import { Provider } from 'react-redux';
import { browserHistory } from 'react-router';
import { syncHistoryWithStore } from 'react-router-redux';
import createRoutes from './routes'; // Contains the routes
import { initStore, persistReduxStore } from './store';
import { appExample } from './container/reducers';
const store = initStore(appExample);
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = { rehydrated: false };
}
componentWillMount() {
persistReduxStore(store)(() => this.setState({ rehydrated: true }));
}
render() {
const history = syncHistoryWithStore(browserHistory, store);
return (
<Provider store={store}>
{createRoutes(history)}
</Provider>
);
}
}
Related
My Expo React Native project is continuously crashing on real device after building.
I used redux saga and its other dependencies for state management and for api call. I used documentation for to learn about. I dont have much knowledge about it.
App.js file
import { SafeAreaView } from "react-native";
import { NativeBaseProvider } from "native-base";
import { InsideStack } from "./src/stackNavigator";
import { Provider } from "react-redux";
import { PersistGate } from "redux-persist/integration/react";
import { store, persistor } from "./src/store";
const config = {
strictMode: "warn",
};
function App() {
return (
<SafeAreaView style={{ flex: 1 }}>
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<NativeBaseProvider config={config}>
<InsideStack />
</NativeBaseProvider>
</PersistGate>
</Provider>
</SafeAreaView>
);
}
export default App;
Redux index file
import { applyMiddleware } from "redux";
import { legacy_createStore as createStore } from "redux";
import createSagaMiddleware from "redux-saga";
import { persistStore, persistReducer } from "redux-persist";
import AsyncStorage from "#react-native-async-storage/async-storage";
import rootSagas from "./RootSagas";
import { rootReducer } from "./RootReducer";
const sagaMiddleware = createSagaMiddleware();
const persistConfig = {
key: "root",
storage: AsyncStorage,
};
const persistedReducer = persistReducer(persistConfig, rootReducer);
const store = createStore(persistedReducer, applyMiddleware(sagaMiddleware));
let persistor = persistStore(store);
sagaMiddleware.run(rootSagas);
export { store, persistor };
root reducer
import { combineReducers } from "#reduxjs/toolkit";
import MainReducer from "../screens/redux/reducers";
export const rootReducer = combineReducers({
mainreducer: MainReducer,
});
Root saga
import { takeEvery, all, fork, SelectEffect, select } from "redux-saga/effects";
import MainSagas from "../screens/redux/saga";
function* watchAndLog() {
yield takeEvery("*", function* logger(action) {
const state = yield select();
console.debug("action", action);
console.debug("state after", state);
});
}
export default function* root() {
console.log(process.env.NODE_ENV);
const allForks = [fork(MainSagas)];
if (process.env.NODE_ENV === "development") {
allForks.unshift(fork(watchAndLog));
}
yield all(allForks);
}
i want to cnnect redux-saga witdh react-native but this error keep happen...
TypeError: store.getState is not a function. (In 'store.getState()',
'store.getState' is undefined
Warning: Failed prop type: Invalid prop store of type function
supplied to Provider, expected object
this is my code
(index.js)
import {AppRegistry} from 'react-native';
import Root from './App';
import {name as appName} from './app.json';
AppRegistry.registerComponent(appName, () => Root);
(App.js)
import React from 'react';
import Store from './store/configureStore'
import {Provider} from 'react-redux';
import {App} from './src/index';
const Root = () => {
return (
<Provider store={Store}>
<App />
</Provider>
);
};
export default Root;
(src/index.js)
import React from 'react';
import Navigator from './Screens/Navigator';
import styled from 'styled-components/native';
const App = ({}) => {
return (
<Navigator/>
);
};
export {App};
(store/cofigurestore.js)
import { applyMiddleware, createStore, compose } from 'redux';
import createSagaMiddleware from 'redux-saga';
import { composeWithDevTools } from 'redux-devtools-extension';
import reducer from '../reducers';
import rootSaga from '../sagas';
const Store = () => {
const sagaMiddleware = createSagaMiddleware();
const middlewares = [sagaMiddleware];
const enhancer = process.env.NODE_ENV === 'production'
? compose(applyMiddleware(...middlewares))
: composeWithDevTools(
applyMiddleware(...middlewares),
);
const store = createStore(reducer, enhancer);
store.sagaTask = sagaMiddleware.run(rootSaga);
return store;
};
export default Store;
(reducer/index.js)
import { combineReducers } from 'redux';
import user from './user';
import post from './post';
// (이전상태, 액션) => 다음상태
const rootReducer = (state, action) => {
switch (action.type) {
// case HYDRATE:
// // console.log('HYDRATE', action);
// return action.payload;
default: {
const combinedReducer = combineReducers({
user,
post,
});
return combinedReducer(state, action);
}
}
};
export default rootReducer;
(sage/index.js)
import { all, fork } from 'redux-saga/effects';
import axios from 'axios';
import postSaga from './post';
import userSaga from './user';
export default function* rootSaga() {
yield all([
fork(postSaga),
fork(userSaga),
]);
}
please help me ......... i want to resolve this problem...... but i don't know how can i do that
In you App.js you should be passing the result of calling you Store function to the Provider and not the function itself.
const Root = () => {
return (
<Provider store={Store()}>
<App />
</Provider>
);
};
Hey I've looked at a bunch of help files now and cant seem to get the issue solved. Most suggestions are using a different setup than I have. The main issue that the others dont have is the LOGOUT feature. Can you suggest another way to handle the LOGOUT?
Here is my index.js for "combine reducers":
import { combineReducers } from 'redux';
import { connectRouter } from 'connected-react-router';
import { LOGOUT_USER } from '../constants/index';
/* App Reducer Files */
import app from './app/reducer';
import accountData from './account/reducer';
import employeeData from './employee/reducer';
import locationData from './location/reducer';
import googleData from './google/reducer';
import requestData from './request/reducer';
import menuItemData from './menuItem/reducer';
import orderData from './order/reducer';
/* Public Reducer Files */
import valorData from './valor/reducer';
const appReducer = history => combineReducers({
router: connectRouter(history),
app,
accountData,
employeeData,
locationData,
googleData,
requestData,
menuItemData,
orderData,
// Public
valorData,
});
const rootReducer = history => (state, action) => {
if (action.type === LOGOUT_USER) {
state = undefined;
}
return appReducer(history, state, action);
};
export default rootReducer;
And my store.js:
import { createStore, applyMiddleware, compose } from 'redux';
import thunkMiddleware from 'redux-thunk';
import { createLogger } from 'redux-logger';
import { routerMiddleware } from 'connected-react-router';
import rootReducer from '../services';
import history from '../history';
const debugware = [];
if (process.env.NODE_ENV !== 'production') {
debugware.push(createLogger({
collapsed: true,
}));
}
export default function configureStore(initialState) {
const store = createStore(
rootReducer(history),
initialState,
compose(
applyMiddleware(
routerMiddleware(history),
thunkMiddleware,
...debugware,
),
),
);
if (module.hot) {
// Enable Webpack hot module replacement for reducers
module.hot.accept('../services', () => {
const nextRootReducer = require('../services/index').default;
store.replaceReducer(nextRootReducer);
});
}
return store;
}
This was working before I upgraded to a new router version. Again the main issue is the LOGOUT. If I just export appReducer it works just fine but doesnt logout.
WOW. The moment I post it I try one more thing...
const rootReducer = history => (state, action) => {
if (action.type === LOGOUT_USER) {
state = undefined;
}
return appReducer(history)(state, action);
};
Why are you returning an undefined state? Instead, return
if (action.type === LOGOUT_USER) {
return{ ...state, user: [] }
}
It basically returns and empty array as user.
I am trying to get a redux-form working but am getting a warning that says:
Unexpected property "form" found in previous state received by the reducer. Expected to find one of the known reducer property names instead: "route", "questionSet". Unexpected properties will be ignored.
When I console.log the props to see my form, form is undefined.
I believe the problem is in the configuration.
my index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import 'babel-polyfill';
import './index.css';
import App from './containers/App/App';
import registerServiceWorker from './registerServiceWorker';
import { Provider } from 'react-redux';
import configureStore from './configureStore'
import createHistory from 'history/createBrowserHistory';
// import { configureStore } from "redux-inject-reducer-and-saga";
const initialState = {};
const history = createHistory();
const store = configureStore(initialState, createHistory);
ReactDOM.render( <Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
registerServiceWorker();
this is my storeConfig.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 './rootReducer';
const sagaMiddleware = createSagaMiddleware();
export default function configureStore(initialState, history) {
const middlewares = [sagaMiddleware, routerMiddleware(history)];
const enhancers = [applyMiddleware(...middlewares)];
const composeEnhancers =
process.env.NODE_ENV !== 'production' &&
typeof window === 'object' &&
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
shouldHotReload: false,
})
: compose;
const store = createStore(
createReducer(),
fromJS(initialState),
composeEnhancers(...enhancers),
);
store.runSaga = sagaMiddleware.run;
store.injectedReducers = {};
store.injectedSagas = {};
if (module.hot) {
module.hot.accept('./rootReducer', () => {
store.replaceReducer(createReducer(store.injectedReducers));
});
}
return store;
}
This is my RootReducer:
import { fromJS } from 'immutable';
import { combineReducers } from 'redux-immutable';
// import { routeReducer } from 'react-router-redux';
import {reducer as formReducer} from 'redux-form/immutable';
export default function createReducer(injectedReducers) {
console.log(formReducer, 'form')
return combineReducers({
// route: routeReducer,
...injectedReducers,
form: formReducer
});
}
Need more text to post (will replace): I can also add the rootReducer in a minute.I can also add the rootReducer in a minute.I can also add the rootReducer in a minute.I can also add the rootReducer in a minute.I can also add the rootReducer in a minute.I can also add the rootReducer in a minute.I can also add the rootReducer in a minute.I can also add the rootReducer in a minute.I can also add the rootReducer in a minute.I can also add the rootReducer in a minute.I can also add the rootReducer in a minute.
I'm trying to implement redux in my universal app, but I've some problems with redux.
I've this configureStore function:
import { createStore, applyMiddleware, compose } from 'redux';
import thunkMiddleware from 'redux-thunk';
import createLogger from 'redux-logger'
import rootReducer from '../reducers/index';
import { routerMiddleware } from 'react-router-redux';
export default function configureStore(history, initialState) {
const reduxRouterMiddleware = routerMiddleware(history);
let finalCreateStore;
if (__DEVELOPMENT__ && __CLIENT__ && __DEVTOOLS__) {
const { persistState } = require('redux-devtools');
const DevTools = require('../containers/DevTools/DevTools');
finalCreateStore = compose(
applyMiddleware(thunkMiddleware)(createStore),
window.devToolsExtension ? window.devToolsExtension() : DevTools.instrument(),
persistState(window.location.href.match(/[?&]debug_session=([^&]+)\b/))
)(createStore);
}
else {
finalCreateStore = applyMiddleware(thunkMiddleware)(createStore);
}
const store = finalCreateStore(rootReducer, initialState);
if (__DEVELOPMENT__ && module.hot) {
module.hot.accept(rootReducer, () => {
store.replaceReducer(rootReducer);
});
}
return store;
}
And then I've my rootReducer file that looks like this:
import { combineReducers } from 'redux';
import environment from './environment';
import general from './general';
import alert from './alert';
import user from './user';
import { routerReducer } from 'react-router-redux'
const rootReducer = combineReducers({
environment,
general,
alert,
user,
routing: routerReducer
});
export default rootReducer;
The problem is that I get this error: Expected the reducer to be a function.
I've googled and searched on StackOverflow(where there are some similar problems), but the answers doesn't works in my case.
So, what I'm doing wrong ? and why ?
Thanks.
try this:
finalCreateStore = compose(
// you write more than one createStore here
applyMiddleware(thunkMiddleware),
window.devToolsExtension ? window.devToolsExtension() : DevTools.instrument(),
persistState(window.location.href.match(/[?&]debug_session=([^&]+)\b/))
)(createStore);
Have you tried
import { combineReducers } from 'redux';
import environment from './environment';
import general from './general';
import alert from './alert';
import user from './user';
import { routerReducer } from 'react-router-redux'
export const rootReducer = combineReducers({
environment: environment,
general: general,
alert: alert,
user: user,
routing: routerReducer
});
export default rootReducer;