Reputation: 4733
This could be a rookie question.
My first experience with redux saga.
the Store:
import { createStore, applyMiddleware, compose } from 'redux';
import createSagaMiddleware from 'redux-saga';
import { createLogger } from 'redux-logger';
import rootReducer from '../reducers/RootReducer';
import rootSagas from '../sagas/RootSaga';
const enhancers = [];
const sagaMiddleware = createSagaMiddleware(),
logger = createLogger(),
initialState = {},
middleware = [ logger, sagaMiddleware ];
if ( process.env.NODE_ENV === 'development' ) {
const devToolsExtension = window.__REDUX_DEVTOOLS_EXTENSION__;
if ( typeof devToolsExtension === 'function' ) {
enhancers.push( devToolsExtension() );
}
}
const composedEnhancers = compose(
applyMiddleware( ...middleware ),
...enhancers
);
const store = createStore( rootReducer, initialState, composedEnhancers );
sagaMiddleware.run( rootSagas );
export default store;
The Action: DashboardAction.js
import actionTypes from '../constants/ActionTypes';
export function getDataForDashboard( response ) {
console.log( 'in the action for dashboard' );
return {
type: actionTypes.GET_DATA_FOR_DASHBOARD,
payload: response
};
}
export function getDataForDashboardSuccess( response ) {
return {
type: actionTypes.GET_DASHBOARD_DATA_SUCCESS,
payload: response
};
}
export function getDataForDashboardError( error ) {
return {
type: actionTypes.GET_DASHBOARD_DATA_ERROR,
payload: error
};
}
The Constants : ActionTypes.js
export default {
GET_DATA_FOR_DASHBOARD: 'GET_DATA_FOR_DASHBOARD',
GET_DASHBOARD_DATA_SUCCESS: 'GET_DASHBOARD_DATA_SUCCESS',
GET_DASHBOARD_DATA_ERROR: 'GET_DASHBOARD_DATA_ERROR'
};
The Saga: RootSaga.js
import { all } from 'redux-saga/effects';
import * as dashboardSagas from './DashboardSaga';
export default function* root() {
yield all( dashboardSagas.GetDataForDashboard() );
}
DashboardSaga.js
import { takeEvery } from 'redux-saga';
import { call, put } from 'redux-saga/effects';
import actionTypes from '../constants/ActionTypes';
import { getData } from '../services/DashboardService';
import {
getDataForDashboardSuccess,
getDataForDashboardError
} from '../actions/DashboardActions';
export function* GetDataForDashboard( action ) {
console.log( 'hello from inner method' );
try {
const response = yield call( getData, action );
//if ( response.id ) {
yield put( getDataForDashboardSuccess( response ) );
// }
} catch ( error ) {
yield put( getDataForDashboardError( error ) );
}
}
export function* watchGetDataForDashboard() {
console.log( 'hello from watcher' );
yield takeEvery( actionTypes.GET_DATA_FOR_DASHBOARD, GetDataForDashboard );
}
The Reducer:DashboardReducer.js /* eslint-disable no-unused-vars */
import actionTypes from '../constants/ActionTypes';
const initialState = {
error: false,
dashboard: {
orderdashboardmodel: {
rfs: '0',
pending: '0',
total: '0'
},
sitesdashboardmodel: {
up: '0',
down: '0',
total: '0',
notmonitored: '0'
},
support: {
open: '0',
late: '0',
escalated: '0'
}
}
};
function getDataForDashboard( state ) {
console.log( 'it comes here' );
return null;
}
function getDashboardSuccess( state, action ) {
console.log( 'IN SUCCESS' );
console.log( action.payload );
return {
...state,
dashboard: {
orderdashboardmodel: {
rfs: action.payload.dashboardModel.Order.RFS,
pending: action.payload.dashboardModel.Order.Pending,
total: action.payload.dashboardModel.Order.Total
},
sitesdashboardmodel: {
up: action.payload.dashboardModel.Sites.Up,
down: action.payload.dashboardModel.Sites.Down,
total: action.payload.dashboardModel.Sites.Total,
notmonitored: action.payload.dashboardModel.Sites.NotMonitored
},
support: {
open: action.payload.dashboardModel.Support.Open,
late: action.payload.dashboardModel.Support.Late,
escalated: action.payload.dashboardModel.Support.Escalated
}
}
};
}
function getDashboardError( state = initialState, action ) {
console.log( action.payload );
return {
...state,
error: true
};
}
export default function DashboardReducer( state = initialState, action ) {
console.log( 'IN REDUCER' );
console.log( action );
switch ( action.type ) {
case actionTypes.GET_DATA_FOR_DASHBOARD:
console.log( 'in the call for dashboard' );
getDataForDashboard( state );
console.log( 'in the call exit' );
break;
case actionTypes.GET_DASHBOARD_DATA_SUCCESS:
console.log( 'in the success call initator' );
getDashboardSuccess( state, action );
break;
case actionTypes.GET_DASHBOARD_DATA_ERROR:
getDashboardError( state, action );
break;
default:
return state;
}
}
the file from where the call is initiated : Dashboard.js
import React from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { Colors } from '../../common/themes';
import Globe from '../../common/assets/images/globe.png';
import DashboardCard from './DashboardCard';
import { DashboardData } from './DashboardData';
import { getDataForDashboard } from '../actions/DashboardActions';
class Dashboard extends React.Component {
componentDidMount() {
console.log( 'called before' );
this.props.getDataForDashboard( 'hello' );
console.log( 'called after' );
}
render() {
return (
<div>some html here</div>
);
}
}
const mapStateToProps = state => ( { dashboard: state.dashboard } );
const mapDispatchToProps = dispatch =>
bindActionCreators( { getDataForDashboard }, dispatch );
export default connect(
mapStateToProps,
mapDispatchToProps
)( Dashboard );
Package.json
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^1.2.0-14",
"@fortawesome/free-solid-svg-icons": "^5.1.0-11",
"@fortawesome/react-fontawesome": "0.1.0-11",
"aws-amplify": "^1.0.4",
"aws-amplify-react": "^1.0.4",
"axios": "^0.18.0",
"bootstrap": "^4.1.3",
"chroma-js": "^1.3.7",
"d3": "^5.5.0",
"i": "^0.3.6",
"npm": "^6.4.0",
"react": "^16.4.1",
"react-dom": "^16.4.1",
"react-loadable": "^5.4.0",
"react-motion": "^0.5.2",
"react-particles-js": "^2.3.0",
"react-redux": "^5.0.7",
"react-router-dom": "^4.3.1",
"react-simple-maps": "^0.12.1",
"reactstrap": "^6.3.1",
"redux": "^4.0.0",
"redux-logger": "^3.0.6",
"redux-saga": "^0.16.0"
},
"devDependencies": {
"babel-core": "^6.26.3",
"babel-eslint": "^8.2.6",
"babel-loader": "^7.1.5",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-polyfill": "^6.26.0",
"babel-preset-env": "^1.7.0",
"babel-preset-flow": "^6.23.0",
"babel-preset-react": "^6.24.1",
"babel-preset-stage-0": "^6.24.1",
"babel-preset-stage-2": "^6.24.1",
"clean-webpack-plugin": "^0.1.19",
"css-loader": "^1.0.0",
"dotenv": "^6.0.0",
"eslint": "^5.2.0",
"eslint-plugin-import": "^2.13.0",
"eslint-plugin-react": "^7.10.0",
"file-loader": "^1.1.11",
"html-webpack-plugin": "^3.2.0",
"jest": "^23.4.2",
"open-browser-webpack-plugin": "0.0.5",
"prettier": "^1.14.0",
"prettier-eslint": "^8.8.2",
"radium": "^0.24.1",
"style-loader": "^0.21.0",
"webpack": "^4.12.2",
"webpack-cli": "^3.0.8",
"webpack-dev-server": "^3.1.4"
},
"jest": {
"verbose": true,
"testURL": "http://localhost/"
}
the problem Saga is never called. Below error:
Uncaught Error: Given action "GET_DATA_FOR_DASHBOARD", reducer "dashboardReducer" returned undefined. To ignore an action, you must explicitly return the previous state. If you want this reducer to hold no value, you can return null instead of undefined
I tried every combination in reducer but this error never goes. May be a fresh pair of eyes can pick what i am missing.
Upvotes: 0
Views: 1931
Reputation: 1545
According to the docs
The reducer is a pure function that takes the previous state and an action, and returns the next state.
You can then see that it's because you are breaking out of your switch statement rather than returning the new state in DashboardReducer.js
. It should instead look something like this:
export default function DashboardReducer( state = initialState, action ) {
switch ( action.type ) {
case actionTypes.GET_DATA_FOR_DASHBOARD:
// note: the function you call returns null. That might not be
// what you are trying to do so just be aware of that.
return getDataForDashboard( state );
case actionTypes.GET_DASHBOARD_DATA_SUCCESS:
return getDashboardSuccess( state, action );
case actionTypes.GET_DASHBOARD_DATA_ERROR:
return getDashboardError( state, action );
default:
return state;
}
}
Upvotes: 2