How to run redux devtools with redux saga? - redux

Trying to run reduxdevtools with redux saga:
Getting this error:
Error
Before running a Saga, you must mount the Saga middleware on the Store using applyMiddleware
This is my jscode:
const store = createStore(
reducer,
applyMiddleware(sagaMiddleware),
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
How can I run this devtool with saga? Alternatively what would work otherwise?
codepen

I've used redux-devtools-extension package as described here, redux-devtools-extension documentation.
After adding the package, I've replaced the store definition with this:
const store = createStore(
reducer,
composeWithDevTools(
applyMiddleware(sagaMiddleware)
)
);
Fixed Codepen Link

The previous answer (by trkaplan) uses an imported method composeWithDevTools from 'redux-devtools-extension' package.
If you don't want to install this package, you may use this code (based on the docs):
const composeEnhancers = typeof window === 'object' && window['__REDUX_DEVTOOLS_EXTENSION_COMPOSE__'] ?
window['__REDUX_DEVTOOLS_EXTENSION_COMPOSE__']({ }) : compose;
const enhancer = composeEnhancers(
applyMiddleware(thunkMiddleware, sagaMiddleware, /*other middleware*/),
/* other store enhancers if any */
);
const emptyReducer = () => {};
const store = createStore(emptyReducer, enhancer);

This is how you configure your redux, redux-devtool-extension and redux-saga for the real projects..
import { createStore, applyMiddleware } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import createSagaMiddleware from 'redux-saga';
import rootReducer from '../reducers';
import rootSaga from '../sagas';
const configureStore = () => {
const sagaMiddleware = createSagaMiddleware();
return {
...createStore(rootReducer, composeWithDevTools(applyMiddleware(sagaMiddleware))),
runSaga: sagaMiddleware.run(rootSaga),
};
};
export default configureStore;

Incase Compose of Redux is used. Then below code is useful.
Step 1: Add chrome Redux DevTools extension.
step 2: npm install redux-devtools-extension.
import { composeWithDevTools } from 'redux-devtools-extension';
const store = createStore(
reducer,
compose(
applyMiddleware(sagaMiddleware),
composeWithDevTools(),
),
);

Related

How can I see my state in Redux Dev Tools (Extension)?

I'm having trouble seeing my state in the Redux Dev Tools. I added the code from zalmoxisus into my createStore, but nothing is displayed. In my reducers I'm also returning the state as a default (using switch case) but still nothing is displayed in state. Can anyone help with this?
try this to use this:
window.devToolsExtension ? window.devToolsExtension() : f => f
instead of:
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
import {combineReducers} from "redux";
import gamesReducer from ... //
const rootReducer = combineReducers({
gamesReducer
});
export default rootReducer;
You used rootReducer like this right?
If it is try redux-devtools-extension package, easy to setup.
Try this
import { createStore, applyMiddleware, compose } from 'redux'
import reduxImmutableStateInvariant from 'redux-immutable-state-invariant'
import thunk from 'redux-thunk'
import rootReducer from '../reducers'
export const middleware = [thunk]
export default function configureStore(initialState) {
return createStore(
rootReducer,
initialState,
compose(
applyMiddleware(thunk, reduxImmutableStateInvariant()),
window.__REDUX_DEVTOOLS_EXTENSION__ ? window.__REDUX_DEVTOOLS_EXTENSION__() : f => f,
),
)
}

React / Redux - Error: Actions must be plain objects. Use custom middleware for async actions

I am getting this error even though I am using redux thunk. Redux store is also set up correctly (I think). I am creating a MERN app and I want to send a POST request to the backend (form submit) to create a new user. The request and response from the server are fine (checked using Postman). I just can not find where the problem is. The action creator which is causing this is :-
import axios from "axios";
export function signupUser(newuser) {
return function (dispatch) {
axios.post("/auth", newuser).then((res) => {
// dispatch
dispatch({
type: "ADDNEW_USER",
payload: res.data,
});
});
};
}
The store setup is :-
import { createStore, applyMiddleware, compose } from "redux";
import thunk from "redux-thunk";
import rootReducer from "./reducers";
const initialState = {};
// const middleware = [thunk];
const store = createStore(
rootReducer,
initialState,
compose(
applyMiddleware(thunk),
window.__REDUX_DEVTOOLS_EXTENSION__ &&
window.__REDUX_DEVTOOLS_EXTENSION__()
)
);
export default store;
The Signup.js component is ->
[Signup.js][1]
and the error is -> [here][2]
[1]: https://paste.ubuntu.com/p/gCX3wQPt9X/
[2]: https://imgur.com/a/6SDmydw

What is the correct way to combine redux-thunk and redux-batched-actions?

What is the correct way to plug redux-batched-actions into my existing Redux store? I am completely confused by the Redux middleware API.
Currently I am using redux-thunk and redux-little-router.
Here is the code source that creates my Redux store:
import { createStore, applyMiddleware, compose, combineReducers } from 'redux'
import thunk from 'redux-thunk'
import { routerForBrowser } from 'redux-little-router'
import reducers from './store'
import routes from './routes'
const { reducer, middleware, enhancer } = routerForBrowser({ routes })
// Combine all reducers and instantiate the app-wide store instance
const allReducers = combineReducers({ ...reducers, router: reducer })
// Build middleware (if devTools is installed, connect to it)
const allEnhancers = (window.__REDUX_DEVTOOLS_EXTENSION__
? compose(
enhancer,
applyMiddleware(thunk, middleware),
window.__REDUX_DEVTOOLS_EXTENSION__())
: compose(
enhancer,
applyMiddleware(thunk, middleware)))
// Instantiate the app-wide store instance
const initialState = window.initialReduxState
const store = createStore(
allReducers,
initialState,
allEnhancers
)
The redux-batched-actions documentation exposes two usages: enableBatching and batchDispatchMiddleware. Which one should I use in my case?
Answering my own question after the return of my expedition into the fabulous source code of redux, redux-thunk, redux-batched-actions, ...
The correct way to do it seems to be using batchDispatchMiddleware, like this:
import { batchDispatchMiddleware } from 'redux-batched-actions'
// ...
const allEnhancers = (window.__REDUX_DEVTOOLS_EXTENSION__
? compose(
enhancer,
applyMiddleware(batchDispatchMiddleware, thunk, middleware),
window.__REDUX_DEVTOOLS_EXTENSION__())
: compose(
enhancer,
applyMiddleware(batchDispatchMiddleware, thunk, middleware)))
Note: I don't know if I could dispatch batched thunks, though. I don't do that in my current application. Use at your own risk!

How to add `redux-logger` on middlewares?

I want to add redux-logger on the middlewares chain. Below is my code:
import {createStore, combineReducers, applyMiddleware, compose} from 'redux';
import reducers from './index';
import createLogger from 'redux-logger';
import thunk from 'redux-thunk';
const logger = createLogger ({
log: 'info',
});
// create the global store
const store = compose (applyMiddleware (thunk, logger)) (createStore) (
reducers
);
export default store;
I will get below error with above code:
applyMiddleware.js:39 Uncaught TypeError: middleware is not a function
at applyMiddleware.js:39
at Array.map (<anonymous>)
at applyMiddleware.js:38
It works fine if I change the apply middleware to this line:
applyMiddleware (thunk, createLogger)
but I need to create the logger with some specific parameters. How can I add the created logger into middleware chain?
import { applyMiddleware, compose, createStore } from 'redux';
import reducers from './index';
import thunk from 'redux-thunk';
import { logger } from 'redux-logger';
const composeEnhancers = typeof window === 'object' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;
const middlewareList = [thunk, logger]
const enhancer = composeEnhancers(
applyMiddleware(...middlewareList)
);
const store = createStore(reducers, enhancer);
export default store;
It should working fine if you change your store into this:
const store = createStore(reducers, compose(applyMiddleware(thunk, logger)));
If that doesn't work, take a look into this issue. It should do the same as above code I think.
https://github.com/gaearon/redux-thunk/issues/35
Fixed this issue by changing the import to import {createLogger} from 'redux-logger';.

Can I Have Redux-Saga and Redux-Thunk Working Together?

I was working with redux-saga but I'm with a problem: the redux-auth-wrapper needs the redux-thunk to do the redirects, so I simply added the thunk in my store:
import {createStore, compose, applyMiddleware} from 'redux';
import createLogger from 'redux-logger';
import {routerMiddleware} from 'react-router-redux';
import {browserHistory} from 'react-router';
import thunk from 'redux-thunk';
import createSagaMiddleware, {END} from 'redux-saga';
import sagas from '../sagas';
import reduxImmutableStateInvariant from 'redux-immutable-state-invariant';
import rootReducer from '../reducers';
import _ from 'lodash';
import {loadState, saveState} from '../connectivity/localStorage';
const persistedState = loadState();
const routerMw = routerMiddleware(browserHistory);
const loggerMiddleware = createLogger();
const sagaMiddleware = createSagaMiddleware();
function configureStoreProd() {
const middlewares = [
// Add other middleware on this line...
routerMw,
sagaMiddleware,
thunk
];
const store = createStore(rootReducer, persistedState, compose(
applyMiddleware(...middlewares)
)
);
store.subscribe(_.throttle(() => {
saveState({
auth: store.getState().auth
});
}, 1000));
sagaMiddleware.run(sagas);
store.close = () => store.dispatch(END);
return store;
}
function configureStoreDev() {
const middlewares = [
// Add other middleware on this line...
// Redux middleware that spits an error on you when you try to mutate your state either inside a dispatch or between dispatches.
reduxImmutableStateInvariant(),
routerMw,
sagaMiddleware,
loggerMiddleware,
thunk
];
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; // add support for Redux dev tools
const store = createStore(rootReducer, persistedState, composeEnhancers(
applyMiddleware(...middlewares)
)
);
store.subscribe(_.throttle(() => {
saveState({
auth: store.getState().auth
});
}, 1000));
if (module.hot) {
// Enable Webpack hot module replacement for reducers
module.hot.accept('../reducers', () => {
const nextReducer = require('../reducers').default; // eslint-disable-line global-require
store.replaceReducer(nextReducer);
});
}
sagaMiddleware.run(sagas);
store.close = () => store.dispatch(END);
return store;
}
const configureStore = process.env.NODE_ENV === 'production' ? configureStoreProd : configureStoreDev;
export default configureStore;
This way works nice without errors, but I'm new in react and I don't know if have problem with redux-saga and redux-thunk working together...
Someone can help me?
No problems to have both. Sagas are just background checkers who react to some actions while thunk let's you have more interesting action creators.
While thunk will act more like synced code, sagas will do it's job in a background.
Both extensions do not change how actions are flying around. Actions still, in the end, are just bare objects like w/o thunk or w/o sagas.
Yes, of course you can use both redux-saga and redux-thunk in this way,
import { createStore, applyMiddleware } from 'redux'
import createSagaMiddleware from 'redux-saga'
import thunk from 'redux-thunk'
import logger from 'redux-logger'
import rootSagas from './sagas'
import rootReducer from './reducers'
const saga = createSagaMiddleware()
const middleWares = [saga, thunk]
export const store = createStore(
rootReducer,
applyMiddleware(...middleWares)
)
saga.run(rootSagas)

Resources