combineReducers causes code to break - reactjs

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

Related

in redux dev toolss my trace option got error (in react)

Here we create a store and i also try + window.REDUX_DEVTOOLS_EXTENSION && window.REDUX_DEVTOOLS_EXTENSION()
import { createStore } from "redux";
import reducer from "./reducer";
import { devToolsEnhancer } from 'redux-devtools-extension';
const store = createStore(reducer ,devToolsEnhancer({ trace: true, traceLimit: 40 }));
export default store;

"export 'createStore' was not found in 'redux'

WARNING in ./node_modules/#redux-saga/core/dist/redux-saga-core.esm.js 1343:21-28
"export 'compose' was not found in 'redux'
# ./node_modules/redux-saga/dist/redux-saga-core-npm-proxy.esm.js
# ./src/store.js
# ./src/App.js
# ./src/index.js
WARNING in ./src/store.js 6:21-32
"export 'createStore' was not found in 'redux'
# ./src/App.js
# ./src/index.js
I'm facing the problem of creating a redux store. Here, I've added the sample code. If I remove the provider from App.js, it's working fine. Can anyone please help me to resolve this issue?
App.js
import React from 'react';
import Layout from './components/Layout';
import { BrowserRouter } from 'react-router-dom';
import { Provider } from 'react-redux';
import { store } from './store'
const App = () => {
return (
<Provider store={store}>
<BrowserRouter>
<Layout/>
</BrowserRouter>
</Provider>
);
}
export default App;
store.js
import { createStore, applyMiddleware } from 'redux'
import createSagaMiddleware from 'redux-saga'
import reducers from './redux';
import sagas from './sagas';
const sagaMiddleware = createSagaMiddleware()
export const store = createStore(
reducers,
applyMiddleware(sagaMiddleware)
)
sagaMiddleware.run(sagas)
reducer
import { combineReducers } from 'redux';
import { reducer as auth } from './AuthRedux'
const reducers = combineReducers({
auth
});
export default reducers;
sagas
import { takeLatest, all } from 'redux-saga/effects';
import api from '../middleware/api';
import { AuthTypes } from '../redux/AuthRedux'
import { signupSaga } from './AuthSaga'
export default function * root () {
const sagaIndex = [
yield takeLatest(AuthTypes.SIGNUP, signupSaga, api),
];
yield all(sagaIndex)
}
I guess it has something to do with the redux and how I import stuff, but I'm not sure what's wrong there.😩😩
Thanks
In the store.js replace
export const store = createStore(
reducers,
applyMiddleware(sagaMiddleware)
)
with
export const store = createStore(
reducers,
{},
applyMiddleware(sagaMiddleware)
)
Just an arrow in the dark coz it worked for me maybe it should work for you

Uncaught Could not find router reducer in state tree, it must be mounted under "router"

React router works normal. But if I add <Redirect> or call from <Link>, I have this exception:
Uncaught Could not find router reducer in state tree, it must be mounted under "router"
rootReducer.js:
import { combineReducers } from 'redux';
import { connectRouter } from 'connected-react-router';
import counterReducer from './Counter/counter.reducer';
import sidebarReducer from './Sidebar/sidebar.reducer';
export default (history) => combineReducers({
router: connectRouter(history),
counter: counterReducer,
sidebar: sidebarReducer,
});
store.js:
import { createBrowserHistory } from 'history';
import { applyMiddleware, compose, createStore } from 'redux';
import { routerMiddleware } from 'connected-react-router';
import createRootReducer from './rootReducer';
export const history = createBrowserHistory();
export default function configureStore(preloadedState) {
const composeEnhancer = compose
const store = createStore(
createRootReducer(history),
preloadedState,
composeEnhancer(
applyMiddleware(
routerMiddleware(history),
),
),
);
if (module.hot) {
module.hot.accept('./rootReducer', () => {
store.replaceReducer(createRootReducer(history));
});
}
console.log(store.getState());
return store;
}
Check the history documentation. If you're using react-router-dom#5.x.x then you should use history#4.10.1 because the latest version of history (v5) only works with react-router-dom#6.x.x

Redux-thunk applyMiddleware

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.

how to initialise all states when press reset button in redux

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

Resources