I'm using a different setup for initializing the redux store (I don't want to use the configureStore method from redux-toolkit) for the purpose of injecting reducers on runtime.
import {
createStore,
combineReducers,
applyMiddleware,
createImmutableStateInvariantMiddleware,
} from "#reduxjs/toolkit";
import { composeWithDevTools } from "#redux-devtools/extension";
import { createCustomMiddleWare} from "./myCustomMiddleWare";
const staticReducers = {};
const middlewares = [
createImmutableStateInvariantMiddleware(),
createCustomMiddleWare(),
];
const createReducer = (asyncReducers = {}) =>
combineReducers({
...staticReducers,
...asyncReducers,
});
export const initializeStore = (initializeState = {}) => {
const store = createStore(
createReducer(),
initializeState,
composeWithDevTools(applyMiddleware(...middlewares))
);
store.asyncReducers = {};
store.injectReducer = (key, reducer) => {
store.asyncReducers[key] = reducer;
store.replaceReducer(createReducer(store.asyncReducers));
return store;
};
return store;
};
export default initializeStore;
I was wondering wether there is a way to add Thunk middleware from redux-toolkit (without installing the redux-thunk package seperately)
I tried using the getDefaultMiddleware() method from redux-toolkit which imports three default middlewares that ships with redux-toolkit including thunk, but since I'm not using it as paramether for the configureStore's middleware callback, I get this error that getDefaultMiddleware is deprecated.
I was able to import one of the default middlewares by using createImmutableStateInvariantMiddleware() function that I found in the official documentations but I could not find a way to import thunk or serlizied middlewares (two other default middlewares of redux-toolkit)
The answer would be to use configureStore and using the middleware callback option.
There is really no good reason that would be using createStore here, that could come down to
const store = configureStore({
reducer: createReducer(),
preloadedState: initializeState,
middleware: getDefaultMiddleware => getDefaultMiddleware().concat(createCustomMiddleWare())
})
Related
I'm working on a React/redux application using redux-persist and I have a huge amount of data to persist, I want to be able to persist my Redux Store ONLY when I click on a button, otherwise I don't want to store my data.
This is my store :
import {
legacy_createStore as createStore,
combineReducers,
applyMiddleware
} from "redux";
import { composeWithDevTools } from "redux-devtools-extension/developmentOnly";
import { persistStore, persistReducer } from "redux-persist";
import storage from "redux-persist-indexeddb-storage";
import thunk from "redux-thunk";
import dataReducer from "./reducers/dataReducer";
const reducer = combineReducers({
data: dataReducer
});
const persistConfig = {
key: "STORE",
storage: storage("STORE")
};
const persistedReducer = persistReducer(persistConfig, reducer);
const initialState = {};
const middleware = [thunk];
const composeEnhancers = composeWithDevTools({
features: {
dispatch: true // dispatch custom actions or action creators
}
});
const store = createStore(
persistedReducer,
initialState,
composeEnhancers(
applyMiddleware(...middleware)
// other store enhancers if any
)
);
const persistor = persistStore(store);
export { persistor };
export default store;
My Index.js look like this :
And I've create a component to show my data :
By doing that : the redux persist data starting from the first render (this is the indexedDb)
What I'm looking for is to set my indexedDB only when I click on the button and trigger the persistData function.
This is my code , So if you have an idea how to achieve this please.
I am trying to get redux-persist working and cannot work out how to do it with the way my app is currently set up.
/**
* Create the store with dynamic reducers
*/
import { createStore, applyMiddleware, compose } from 'redux';
import { fromJS } from 'immutable';
import { routerMiddleware } from 'react-router-redux';
import createSagaMiddleware from 'redux-saga';
import thunk from 'redux-thunk';
import createReducer from './reducers';
import { persistStore, persistReducer } from 'redux-persist'
import storage from 'redux-persist/lib/storage'
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,
thunk,
routerMiddleware(history),
];
const enhancers = [
applyMiddleware(...middlewares),
];
// If Redux DevTools Extension is installed use it, otherwise use Redux compose
/* eslint-disable no-underscore-dangle */
const composeEnhancers =
process.env.NODE_ENV !== 'production' &&
typeof window === 'object' &&
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
// TODO Try to remove when `react-router-redux` is out of beta, LOCATION_CHANGE should not be fired more than once after hot reloading
// Prevent recomputing reducers for `replaceReducer`
shouldHotReload: false,
})
: compose;
/* eslint-enable */
const store = createStore(
createReducer(),
fromJS(initialState),
composeEnhancers(...enhancers)
);
// Extensions
store.runSaga = sagaMiddleware.run;
store.injectedReducers = {}; // Reducer registry
store.injectedSagas = {}; // Saga registry
// Make reducers hot reloadable, see http://mxs.is/googmo
/* istanbul ignore next */
if (module.hot) {
module.hot.accept('./reducers', () => {
store.replaceReducer(createReducer(store.injectedReducers));
});
}
return store;
}
Where am I supposed to add redux-persist in here to make it connect to the store and save to localstorage?
I have tried a lot of different ways, all wrong, with a huge range of errors.. So no point posting all of them up.
Thanks in advance for helping :)
I'm not sure if this is of any use as I'm using redux-thunk and redux-localstorage (instead of redux-persist), but this works for me:
import { createStore, compose, applyMiddleware } from 'redux';
import rootReducer from '../reducers/rootReducer';
import thunk from 'redux-thunk';
import persistState from 'redux-localstorage';
const enhancer = compose(
applyMiddleware(thunk),
persistState(/*paths, config*/)
);
export default function configureStore() {
return createStore(
rootReducer,
window.__REDUX_DEVTOOLS_EXTENSION__ &&
window.__REDUX_DEVTOOLS_EXTENSION__(),
enhancer
);
}
I have been getting the following error since sometime in my console, i have no idea what it means and why it is originating. Please spread some light on this matter.
it says:
persistReducer.js:50 Uncaught TypeError: action.rehydrate is not a function
at _rehydrate (persistReducer.js:50)
at persistReducer.js:54
redux-persist version on package.json: "^5.6.11"
locked version: "5.9.1"
Store configuration code:
import thunk from 'redux-thunk';
import { persistStore } from 'redux-persist';
import { History, createBrowserHistory } from 'history';
import { createUserManager, loadUser } from "redux-oidc";
import { routerReducer, routerMiddleware } from 'react-router-redux';
import { createStore, applyMiddleware, compose, combineReducers, GenericStoreEnhancer, Store, StoreEnhancerStoreCreator, ReducersMapObject } from 'redux';
import * as StoreModule from './reducers';
import { ApplicationState, reducers } from './reducers';
import userManager from "./utils/userManager";
// Create browser history to use in the Redux store
const baseUrl = document.getElementsByTagName('base')[0].getAttribute('href')!;
const history = createBrowserHistory({ basename: baseUrl });
export default function configureStore(history: History, initialState?: ApplicationState) {
// Build middleware. These are functions that can process the actions before they reach the store.
const windowIfDefined = typeof window === 'undefined' ? null : window as any;
// If devTools is installed, connect to it
const devToolsExtension = windowIfDefined && windowIfDefined.__REDUX_DEVTOOLS_EXTENSION__ as () => GenericStoreEnhancer;
const createStoreWithMiddleware = compose(
applyMiddleware(thunk, routerMiddleware(history)),
devToolsExtension ? devToolsExtension() : <S>(next: StoreEnhancerStoreCreator<S>) => next
)(createStore);
// Combine all reducers and instantiate the app-wide store instance
const allReducers = buildRootReducer(reducers);
const store = createStoreWithMiddleware(allReducers, initialState) as Store<ApplicationState>;
loadUser(store, userManager);
// Enable Webpack hot module replacement for reducers
if (module.hot) {
module.hot.accept('./reducers', () => {
const nextRootReducer = require<typeof StoreModule>('./reducers');
store.replaceReducer(buildRootReducer(nextRootReducer.reducers));
});
}
const persistor = persistStore(store);
return { store, persistor };
}
function buildRootReducer(allReducers: ReducersMapObject) {
return combineReducers<ApplicationState>(Object.assign({}, allReducers, { routing: routerReducer }));
}
// Get the application-wide store instance, prepopulating with state from the server where available.
const initialState = (window as any).initialReduxState as ApplicationState;
export const { store, persistor } = configureStore(history, initialState);
if you are working on localhost and using redux-devtools try to check Access File Url checkbox on extension options.
you can manage your chrome extensions by typing chrome://extensions/ in the address bar or by going to the setting and chose extensions from left menu.
I get this error when using redux devtools, remove this and it should go away.
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
Your code is using API of an older redux-persist version.
Refer to Basic Usage for the updated API:
import { persistStore, persistReducer } from 'redux-persist'
const persistConfig = {
key: 'root',
storage,
}
const allReducers = persistReducer(persistConfig, buildRootReducer(reducers));
I'm working on a project with the React Redux Router, and am trying to change the page. When a component dispatches a "push" action, I see the "##router/LOCATION_CHANGE" come through, but nothing changes.
I do have the routerMiddleware applied as well,
import thunk from 'redux-thunk';
import { routerMiddleware } from 'react-router-redux';
import createHistory from 'history/createBrowserHistory'
import rootReducer from '../reducers';
export const history = createHistory();
const middleware = routerMiddleware(history)
export function configureStore(initialState) {
return createStore(
rootReducer,
initialState,
applyMiddleware(thunk),
applyMiddleware(middleware)
);
}
any thoughts as to what I'm doing incorrectly?
applyMiddleware expects a list of middlewares, so you're using it wrong:
Please change it to:
export const history = createHistory();
const middleware = routerMiddleware(history)
export function configureStore(initialState) {
return createStore(
rootReducer,
initialState,
applyMiddleware(thunk,middleware)
);
}
This also explains why switching them worked (the store received another middleware).
I am trying to call the reducer from the component and want to render that in component , but when I am trying to store the reducer in the createStore() method of redux above error is coming. My Code is like this:-
import { applyMiddleware, compose, createStore } from 'redux'
import thunk from 'redux-thunk'
import { browserHistory } from 'react-router'
import makeRootReducer from './reducers'
import { updateLocation } from './location'
import allReducers from './reducers';
export default (initialState = {}) => {
// ======================================================
// Middleware Configuration
// ======================================================
const middleware = [thunk]
// ======================================================
// Store Enhancers
// ======================================================
const enhancers = []
let composeEnhancers = compose
if (__DEV__) {
const composeWithDevToolsExtension = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
if (typeof composeWithDevToolsExtension === 'function') {
composeEnhancers = composeWithDevToolsExtension
}
}
// ======================================================
// Store Instantiation and HMR Setup
// ======================================================
const store = createStore(
allReducers,
makeRootReducer(),
initialState,
composeEnhancers(
applyMiddleware(...middleware),
...enhancers
)
)
I am getting error :Uncaught Error: Expected the enhancer to be a
function
You are passing in two reducers to the createStore function instead of one.
Since the third argument to createStore is always the enhancer function it thinks that the 'initiaeState' variable is an enhancer function since you are passing this in as the thid argument to createStore.
createStore expects to receive the following arguments:
reducer (Function): A reducing function that returns the next state
tree, given the current state tree and an action to handle.
[preloadedState] (any): The initial state. You may optionally
specify it to hydrate the state from the server in universal apps,
or to restore a previously serialized user session. If you produced
reducer with combineReducers, this must be a plain object with the
same shape as the keys passed to it. Otherwise, you are free to pass
anything that your reducer can understand.
[enhancer] (Function): The store enhancer. You may optionally
specify it to enhance the store with third-party capabilities such
as middleware, time travel, persistence, etc. The only store
enhancer that ships with Redux is applyMiddleware().
Remember the root reducer in your app should combine all your reducers into one single reducer.
From the Redux docs
First and foremost, it's important to understand that your entire
application really only has one single reducer function
I encountered a similar error TypeError: enhancer(...) is not a function because I was passing a function instead of a plain object as the initial state.
Ie my error was due to missing brackets on my initial state generator function:
const store = createStore(
reducer,
testState, // <<< missing brackets!! doh
applyMiddleware(sagaMiddleware)
)
When it should have been:
const store = createStore(
reducer,
testState(),
applyMiddleware(sagaMiddleware)
)
In my case it was a wrong import.
❌ Wrong import:
import { applyMiddleware, createStore } from "redux";
import rootReducer from "../reducers/index";
import createSagaMiddleware from "redux-saga";
import rootSaga from "redux/sagas";
import { compose } from "#material-ui/system"; // <= ERROR: wrong compose
const sagaMiddleware = createSagaMiddleware();
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
rootReducer,
{},
composeEnhancers(applyMiddleware(sagaMiddleware))
);
sagaMiddleware.run(rootSaga);
export default store;
✅ Correct import:
import { applyMiddleware, compose, createStore } from "redux"; // <= Correct!
import createSagaMiddleware from "redux-saga";
import rootSaga from "redux/sagas";
import rootReducer from "../reducers/index";
const sagaMiddleware = createSagaMiddleware();
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
rootReducer,
{},
composeEnhancers(applyMiddleware(sagaMiddleware))
);
sagaMiddleware.run(rootSaga);
export default store;