Actions must be plain objects while using redux thunk - javascript

I am using Redux thunk to dispatch multiple actions.
I have a store.js file
// store.js
import rootReducer from '../reducers/setInitData'; // reducer file
import { applyMiddleware, createStore } from 'redux';
import thunk from 'redux-thunk';
const middleware = applyMiddleware(thunk);
export default createStore(rootReducer, middleware, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());
I have an app.js
import React from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import CampaignCreate from './CampaignCreate' // component
import store from './store/store' // store.js
store.dispatch((dispatch) => {
dispatch({
type: 'SET_STATE',
payload : {
}
})
dispatch({
type : 'DISPLAY_REACT_COMPONENTS',
payload : {
dataLoadComplete : true
}
})
});
render(
<Provider store={store}>
<div id="campaign-init">
<CampaignCreate />
</div>
</Provider>,
document.getElementById('campaigns-react')
)
When I run my code I see the following error in my console:
Uncaught Error: Actions must be plain objects. Use custom middleware for async actions.
What is going wrong with the above code?

It's not the correct way to configure middlewares with redux devtools, according to redux devtools' readme, you should do this:
// don't forget import { compose } from 'redux'
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(reducer, composeEnhancers(middleware));

Related

Cant access store with mapStateToProps

Im new to react, I'm trying to setup the login system with redux. In my Login component I'm using mapStateToProps with the connect method that react-redux offers.
When I tried to get what I needed from the store It kept saying that it was undefined. This is a snippet of my Login component:
function mapStateToProps(state) {
return {
loggingIn: state.authentication.loggedIn,
};
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(userActions, dispatch),
alertActions: bindActionCreators(alertActions, dispatch),
};
}
export default connect(mapStateToProps, mapDispatchToProps)(Login)
Here's how I tried to combine reducers:
import { combineReducers } from 'redux';
import authentication from './userReducer';
import alert from './alertReducer'
const rootReducer = () => combineReducers({
authentication,
alert
});
export default rootReducer;
However I couldn't access the logginIn props in the Login component. After trouble shooting for some frustrating hours I got it to work by removing the arrow function to this:
const rootReducer = combineReducers({
Can someone tell me why the arrow function didn't work? Thanks
Update: Here's how I imported the root reducer in the index.js file
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import { Provider } from 'react-redux'
import { createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk';
import rootReducer from './reducers'
const store = createStore(rootReducer, applyMiddleware(thunk));
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>, document.getElementById('root'))
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
serviceWorker.unregister();
The docs tells you to call combineReducers to provide the root reducer.
The createStore method expects a reducer, not a function to call to get this reducer.
In addition to Vinicius' answer, you can refactor your combineReducers() call even more.
Instead of:
const rootReducer = () => combineReducers({
authentication,
alert
});
export default rootReducer;
which I have seen others do before, I guess personally the less code I need to write the cleaner, as long as it doesn't become esoteric looking, anyway just write it like this:
export default combineReducers({
authentication,
alert
});
You export and call the combineReducers() all in one go. Oh and to import it, since we removed rootReducer just do:
import reducers from "./reducers";
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
reducers,
composeEnhancers(applyMiddleware(reduxThunk))
);

Redux-form: form is undefined in props

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.

Uncaught TypeError: Providing your root Epic to createEpicMiddleware(rootEpic)

I am getting this error
Uncaught TypeError: Providing your root Epic to
createEpicMiddleware(rootEpic) is no longer supported, instead use
epicMiddleware.run(rootEpic)
When simply using
import 'rxjs'
import { createStore, combineReducers, applyMiddleware } from 'redux'
import { reducer as formReducer } from 'redux-form'
import thunk from 'redux-thunk'
import promise from 'redux-promise-middleware'
import { createEpicMiddleware, combineEpics } from 'redux-observable'
import app from './app'
// Bundling Epics
const rootEpic = combineEpics(
)
// Creating Bundled Epic
const epicMiddleware = createEpicMiddleware(rootEpic)
// Define Middleware
const middleware = [
thunk,
promise(),
epicMiddleware
]
// Define Reducers
const reducers = combineReducers({
form: formReducer
})
// Create Store
export default createStore(reducers,window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__(), applyMiddleware(...middleware))
Kindly help to resolve this
First, take a look at this document: Official Redux-Observable Document because we're using the newest version of Redux-Observable, then reviewing its document is quite helpful.
After reviewing the document, let's see a small example project (Counter app):
This is the root.js file which contains my Epics and Reducers after bundling.
// This is a sample reducers and epics for a Counter app.
import { combineEpics } from 'redux-observable';
import { combineReducers } from 'redux';
import counter, {
setCounterEpic,
incrementEpic,
decrementEpic
} from './reducers/counter';
// bundling Epics
export const rootEpic = combineEpics(
setCounterEpic,
incrementEpic,
decrementEpic
);
// bundling Reducers
export const rootReducer = combineReducers({
counter
});
And this is store.js where I define my store before using it.
import { createStore, applyMiddleware } from 'redux';
import { createEpicMiddleware } from 'redux-observable';
import { rootEpic, rootReducer } from './root';
import { composeWithDevTools } from 'redux-devtools-extension';
const epicMiddleware = createEpicMiddleware();
const middlewares = [
epicMiddleware
]
const store = createStore(
rootReducer,
composeWithDevTools(applyMiddleware(middlewares))
);
epicMiddleware.run(rootEpic);
export default store;
In order to successfully implement redux-observable, we have to obey this order:
Creating epicMiddleware using createEpicMiddleware() method
Using the applyMiddleware() method to register the epicMiddleware (the redux-devtools-extension is optional)
Calling the epicMiddleware.run() with the rootEpic we created earlier.
This is the instruction from the Redux-Observable Document
For more information, you could find it here: : Setting Up The Middleware:
Try this
import 'rxjs'
import { createStore, combineReducers, applyMiddleware } from 'redux'
import { reducer as formReducer } from 'redux-form'
import thunk from 'redux-thunk'
import promise from 'redux-promise-middleware'
import { createEpicMiddleware, combineEpics } from 'redux-observable'
import app from './app'
// Bundling Epics
const rootEpic = combineEpics(
)
// Creating Bundled Epic
const epicMiddleware = createEpicMiddleware();
// Define Middleware
const middleware = [
thunk,
promise(),
epicMiddleware
]
// Define Reducers
const reducers = combineReducers({
form: formReducer
})
// Create Store
const store = createStore(reducers,window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__(), applyMiddleware(...middleware))
epicMiddleware.run(rootEpic);
export default store
official documentation createEpicMiddleware.
Well, have you tried:
import { epicMiddleware, combineEpics } from 'redux-observable'
const epicMiddleware = epicMiddleware.run(rootEpic)
?

Is this the correct way to implement middleware in redux?

I am attempting to debug a redux store for async actions. But I am failing to pass dispatch as a function so I will be posting series of questions to help myself find my issue. The first thing I need to ensure is that I am applying redux-thunk properly. So is this the correct way to implement redux middleware?
import { createStore,applyMiddleware,combineReducers,compose } from 'redux';
import thunk from 'redux-thunk';
import {createLogger} from 'redux-logger';
import {inventoryFilter,availableAttributes} from '../reducers/reducer';
const logger=createLogger()
const Store = createStore(
///combine imported reducers
combineReducers({
activeFilter:inventoryFilter,
availableAttributes:availableAttributes
},{},applyMiddleware(thunk,logger)
));
export default Store;
No. You're passing the middleware enhancer as an argument to combineReducers, when it should actually be an argument to createStore.
Here's how I would write it:
import { createStore,applyMiddleware,combineReducers,compose } from 'redux';
import thunkMiddleware from 'redux-thunk';
import {createLogger} from 'redux-logger';
import {inventoryFilter,availableAttributes} from '../reducers/reducer';
const rootReducer = combineReducers({
activeFilter:inventoryFilter,
availableAttributes:availableAttributes
});
const loggerMiddleware = createLogger();
const middlewareEnhancer = applyMiddleware(thunkMiddleware, loggerMiddleware);
const store = createStore(rootReducer, middlewareEnhancer);
export default store;

Redux Devtool (chrome extension) not displaying state

I am new with Redux and newer with Redux devtool.
I made a simple app in which you click on a user and it display some data about him.
So basically in the state I have the current selected user.
But I don't know why the state keep beeing empty in redux devtool. (not in the app)
Here is where I create my store :
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'));
And here is the action :
export const USER_SELECTED = 'USER_SELECTED'
export function selectUser(user){
return {
type : USER_SELECTED,
payload : user
}
}
Here is a reducer :
import {USER_SELECTED} from '../actions/index'
export default function (state = null,action){
switch(action.type){
case USER_SELECTED :
return action.payload
}
return state
}
And finally a call to the action :
this.props.selectUser(user)
The app works very well but I am probably missing something.
Thanks for your help !
Try the following if you have setup the store using a middleware
import { createStore, applyMiddleware, compose } from 'redux';
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(reducer, /* preloadedState, */ composeEnhancers(
applyMiddleware(...middleware)
));
Did you add this line to your store?
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
github.com/zalmoxisus/redux-devtools-extension#11-basic-stor‌​e
I was looking at how I did it years ago and this would do the trick:
const store = createStore(reducers,
window.devToolsExtension && window.devToolsExtension()
)
For potential redux newcomers working on older projects/tutorials know that
window.devToolsExtensionis deprecated in favor ofwindow.REDUX_DEVTOOLS_EXTENSION`, and will be removed in next version of Redux DevTools: https://git.io/fpEJZ
as previously answered, replace with window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
I tried everything but still Redux was not showing in dev tools,
so I tried this chrome extension. Also reload after installing this extension.
https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd/related?hl=en
It worked like a charm
Also the files,
store.js
import { createStore, applyMiddleware } from "redux"; // importing redux,redux-thunk(for my own use) and redux-devtools-extension
import thunk from 'redux-thunk';
import { composeWithDevTools } from 'redux-devtools-extension';
const initialState = {}; // declaring the variable with empty state
const composeEnhancers = composeWithDevTools({});
const store = createStore( // creating the store
finalReducer,
initialState,
composeEnhancers(applyMiddleware(thunk)) // you can leave this as it is if no middleware
);
App.js
import { Provider } from 'react-redux'; // importing the provider and store
import store from './store' // using store
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
I was facing the same issue.
I didn't get permanent solution yet but here is the workaround -
Change the chrome DevTools theme, only once it is required.
Now open devtools, you find the extension tab in DevTools.
You can again change the theme whatever you want to keep and this will fix your problem.

Categories