Excuse the lengthy explanation, but it shows all steps...
Let's walk through this example: A user goes to a Dashboard
view...
client/src/containers/dashboard.js (this HOC
container basically just passes Redux actions and state to a DashboardPanels
component.)
import React from 'react';
import { connect } from 'react-redux';
import { getDashboardData } from '../actions/dashboardActions';
import DashboardPanels from '../components/dashboard/DashboardPanels';
export default connect(state => ({ dashboardData: state.dashboard.data }), { getDashboardData })(props => <DashboardPanels {...props} />)
client/src/components/dashboard/DashboardPanels (the DashboardPanels
component is mounted and then executes the passed down Redux getDashboardData()
action in its componentDidMount
lifecycle method -- NOTICE: If data hasn't populated yet, it shows a spinner!)
import React, { Component } from 'react';
import { Row } from 'antd';
import PageContainer from '../app/panels/pageContainer';
import MessagesPanel from './messagesPanel';
import PlansPanel from './plansPanel';
import PromotionalsPanel from './promotionalsPanel';
import Spinner from '../app/loaders/Spinner';
import SubcribersPanel from './subscribersPanel';
import TemplatesPanel from './templatesPanel';
import TransactionsPanel from './transactionsPanel';
export default class Dashboard extends Component {
componentDidMount = () => this.props.getDashboardData();
render = () => (
!this.props.dashboardData
? <Spinner />
: <PageContainer>
<Row style={{ marginTop: 30 }}>
<SubcribersPanel {...this.props.dashboardData} />
<PlansPanel {...this.props.dashboardData} />
<PromotionalsPanel {...this.props.dashboardData} />
<TransactionsPanel {...this.props.dashboardData} />
<MessagesPanel {...this.props.dashboardData} />
<TemplatesPanel {...this.props.dashboardData} />
</Row>
</PageContainer>
)
}
client/src/actions/dashboardActions.js (this makes an AJAX request to the express
API server)
import { app } from './axiosConfig';
import * as types from './types';
const getDashboardData = () => dispatch => (
app.get(`dashboard`)
.then(({data}) => dispatch({ type: types.SET_DASHBOARD_DATA, payload: data }))
.catch(err => dispatch({ type: types.SERVER_ERROR, payload: err }))
)
export {
getDashboardData
}
routes/dashboard.js (front-end AJAX request hits the express
API server's dashboard route -- passes through authentication, then gets sent to the getAll
controller)
const { getAll } = require('../controllers/dashboard);
const { requireRelogin, requireAuth } = require('../services/strategies');
app.get('/api/dashboard', requireAuth, getAll);
}
controllers/dashboard.js (The getAll
controller receives the request, queries the PostgresSQL DB and returns JSON
or what you referred to as a nested object in an array [{...}]
. NOTICE that I'm using res.send()
with the ...spread
operator!)
const { db, query: { getAllDashboardDetails }} = require('../database);
const { beginofMonth, endofMonth, parseStringToNum, sendError } = require('../shared/helpers');
// GETS ALL DASHBOARD DATA
exports.getAll = async (req, res, done) => {
const beginMonth = beginofMonth();
const endMonth = endofMonth();
try {
const dashboard = await db.many(getAllDashboardDetails, [req.session.id, beginMonth, endMonth])
return res.status(201).send(...dashboard);
} catch (err) { return sendError(err, res, done); }
}
dashboard JSON
is structured like so on the back-end:
dashboard [{
subscribers: '146',
inactivesubscribers: '12',
plans: '12',
popularplans: [ [Object], [Object], [Object], [Object], [Object], [Object] ],
promotionals: '12',
popularpromotionals: [ [Object], [Object], [Object], [Object], [Object], [Object] ],
credits: '5',
creditstotal: '149.95',
dues: '5',
duestotal: '149.95',
charges: '7',
chargestotal: '209.93',
refunds: '7',
refundstotal: '209.93',
messages: '5',
activetemplates: '4',
inactivetemplates: '4'
}]
client/src/reducers/index.js (however, because we used res.send()
with the ...spread
operator, it now becomes a simple object by the time it is saved to Redux's state
via the dashboardReducer
)
import { routerReducer as routing } from 'react-router-redux';
import { combineReducers } from 'redux';
import * as types from '../actions/types';
const dashboardReducer = (state = {}, { payload, type }) => {
switch (type) {
case types.SET_DASHBOARD_DATA:
return {
...state,
data: payload
};
default: return state;
}
}
export default = combineReducers({
dashboard: dashboardReducer,
routing
});
Redux's dashboard
state is now structured like so:
dashboard: {
data: {
subscribers: '146',
inactivesubscribers: '12',
plans: '12',
popularplans: [ [Object], [Object], [Object], [Object], [Object], [Object] ],
promotionals: '12',
popularpromotionals: [ [Object], [Object], [Object], [Object], [Object], [Object] ],
credits: '5',
creditstotal: '149.95',
dues: '5',
duestotal: '149.95',
charges: '7',
chargestotal: '209.93',
refunds: '7',
refundstotal: '209.93',
messages: '5',
activetemplates: '4',
inactivetemplates: '4'
}
}
Since the DashboardPanels
is connected to Redux via a HOC
component, we can now access Redux's state.dashboard.data
via this.props.dashboardData
.
And the result:
