Redux-thunk applyMiddleware - reactjs

Just wondering why in this setup he put thunk in array and spread the middleware argument what is the difference between by just passing applyMiddleware (thunk).
import { createStore, applyMiddleware } from "redux";
import { composeWithDevTools } from "redux-devtools-extension";
import thunk from "redux-thunk";
import rootReducer from "./reducers";
const initialState = {};
const middleware = [thunk];
const store = createStore(
rootReducer,
initialState,
composeWithDevTools(applyMiddleware(...middleware))
);
export default store;

There is none. It is just preference, if you check the applyMiddleware signature it can take up to 5 middleware directly or if you want more than that you need this syntax.

Related

Clear the redux store after logout

I have created a redux store below, the only thing I want to clear the redux store when user logout from the application, so store having the latest and updated data of currently logged user.
import { createStore, applyMiddleware, compose } from 'redux';
import { persistStore, persistReducer } from 'redux-persist';
import storage from 'redux-persist/lib/storage';
import rootReducer from './Reducers';
import { sessionService } from 'redux-react-session';
import thunk from 'redux-thunk';
const persistedReducer = persistReducer({ key: 'root', storage }, rootReducer);
const composeEnhancers =
(typeof window !== 'undefined' &&
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) ||
compose;
export const store = createStore(
persistedReducer,
composeEnhancers(
applyMiddleware(thunk)
)
);
export const persistor = persistStore(store);
sessionService.initSessionService(store);
The above snippet I wrote to create the store using redux persist
please suggest

How to set up redux-persist with thunk, middleware and immutable JS?

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
);
}

Dispatching `push` does not change route in React Redux Router

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).

Uncaught Error: Expected the enhancer to be a function

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;

combineReducers causes code to break

This is subsequent to the thread I posted here
After lot of troubleshooting I found that this code works without any problems
import React from 'react';
import { createStore, combineReducers, applyMiddleware } from 'redux';
import createLogger from 'redux-logger';
import thunkMiddleware from 'redux-thunk';
import { Provider } from 'react-redux';
import DataTableReducer from './reducers/DataTableReducer';
import DimensionPickerReducer from './reducers/DimensionPickerReducer';
const loggerMiddleware = createLogger();
const store = createStore(
DimensionPickerReducer,
applyMiddleware(
thunkMiddleware,
loggerMiddleware
)
);
export default store;
But if I replace my single reducer with a combine reducer call like
import React from 'react';
import { createStore, combineReducers, applyMiddleware } from 'redux';
import createLogger from 'redux-logger';
import thunkMiddleware from 'redux-thunk';
import { Provider } from 'react-redux';
import DataTableReducer from './reducers/DataTableReducer';
import DimensionPickerReducer from './reducers/DimensionPickerReducer';
const loggerMiddleware = createLogger();
const store = createStore(
combineReducers({
DataTableReducer,
DimensionPickerReducer
}),
applyMiddleware(
thunkMiddleware,
loggerMiddleware
)
);
export default store;
I immediately start getting errors by the DimensionPicker control that the mandatory props were not specified.
So the combineReducer method is not working for me.
I am uploaded a sample project here which shows the problem.
https://github.com/abhitechdojo/MovieLensReact
You will have to run npm install after doing a git clone
With combined reducers your store will have data structure like that:
{
DimensionPickerReducer: {
dimenisionName: '',
pickerIsLoading: false,
pickerError: '',
currentAttribute: '',
attributeList: []
},
DataTableReducer: {
tableData: [],
tableIsLoading:false,
tableError: ''
}
}
So you should adjust your containers to work with combined store. For example in DimensionPickerContainer.js you should change mapStateToProps function:
const mapStateToProps = (state) => {
return {
attributeList : state.DimensionPickerReducer.attributeList,
currentAttribute : state.DimensionPickerReducer.currentAttribute
}
}
You can also name your reduces in store, so they would not look ugly in data structure. E.g. combineReducers({ dimensionPicker: DimensionPickerReducer, dataTable: DataTableReducer})

Resources