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).
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'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())
})
in my app i'm using redux with redux-thunk.there is on RESET Button, when user click it i want INITIALIZE all redux state instead of window.location.reload().
index.js (reducers index file)
import { combineReducers } from 'redux';
import { reducer as reduxFormReducer } from "redux-form";
import authReducer from './auth_reducer';
import main from './main'
import BookingData from './booking_reducer';
import StepOne from './stepone';
import StepTwo from './stepTwo'
const rootReducer = combineReducers({
form: reduxFormReducer,
auth: authReducer,
Main:main,
StepOneReducer:StepOne,
StepTwoReducer:StepTwo,
BookingData:BookingData,
})
export default rootReducer;
here each value of object contains separate reducer file and each reducer file has number of states
App.js (root file)
import ReactDOM from "react-dom";
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import reduxThunk from 'redux-thunk';
import { composeWithDevTools } from 'redux-devtools-extension';
import AppRouter from './routers/AppRouter';
import reducers from './reducers';
const middleware = [
reduxThunk,
];
const store = createStore(reducers, composeWithDevTools(
applyMiddleware(...middleware),
// other store enhancers if any
));
const token = localStorage.getItem('token');
if(token){
store.dispatch({type:AUTH_USER});
}
ReactDOM.render(
<Provider store={store}>
<AppRouter />
</Provider>
, document.getElementById('app'));
so my problem is when press Reset Button it will call action Creator, it will dispatch the action when it comes to the reducer(index reducer) I'm unable reset all state.
i saw this Question also but here i don't want to change my index reducer file structure because I need export both and project logic also get mess.
how can i initialize all redux state when user click Reset Button
If I understand you correctly, then I am doing a similar thing in my apps:
I reset my entire redux state by dispatching a 'reset', or 'initialize' action, and have a case in all reducers for this action, where I set the state to the initial values.
actually i was exporting AppReducer instead of rootReducer
import { combineReducers } from 'redux';
import { reducer as reduxFormReducer } from "redux-form";
import authReducer from './auth_reducer';
import main from './main'
import BookingData from './booking_reducer';
import StepOne from './stepone';
import StepTwo from './stepTwo'
import {RESET} from '../actions/types';
const AppReducer = combineReducers({
form: reduxFormReducer,
auth: authReducer,
Main:main,
StepOneReducer:StepOne,
StepTwoReducer:StepTwo,
BookingData:BookingData,
})
const rootReducer = (state, action) => {
if (action.type === RESET) {
console.log('reset action inside root');
state = undefined
}
return AppReducer(state, action)
}
export default rootReducer;
worked Dan Abramov solution
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;
const rootReducer = combineReducers({
router: routerStateReducer,
todos,
})
const createStoreWithMiddleware = compose(
applyMiddleware(thunk),
reduxReactRouter({ routes, createHistory })
)(createStore)(reducer);
export default function configureStore(initialState) {
const store = createStoreWithMiddleware(rootReducer, initialState)
It is giving me createStoreWithMiddleware is not a function.. Why this ?
You're executing the result of compose (which returns a function). So instead of setting createStoreWithMiddleware to the returned function, you are setting it to the executed result with the variable reducer.
Not sure what the variable reducer in this context is since you have rootReducer defined above. Your code should probably read:
const createStoreWithMiddleware = compose(
applyMiddleware(thunk),
reduxReactRouter({ routes, createHistory })
)(createStore)
doing so will define createStoreWithMiddleware as an extended createStore function, which can then receive your rootReducer and initialState.