-
Notifications
You must be signed in to change notification settings - Fork 84
Demo: Counter App
This is a short write up of a Demo application. This application will have two routes:
- /: The main route to increase and decrease a counter
- /stats: View how often the decrease/increase button has been clicked
Create a fresh project:
mkdir counter-demo && cd counter-demo
yo react-webpack-redux
npm install --save react-router
Further we will need two actions
, one for increasing the counter, and one for decreasing it, so lets add them:
yo react-webpack-redux:action increase
yo react-webpack-redux:action decrease
Let's also create a new container
for the stats:
yo react-webpack-redux:container Stats
We will also need components
to display the counter UI and the stats:
yo react-webpack-redux:component counter
yo react-webpack-redux:component stats
The last thing we need is a reducer to keep track of our counter and the clicks:
yo react-webpack-redux:reducer counter
Lets start the app to see our changes live from now on:
npm start
Our reducer will handle both actions, the increase and the decrease. Further it will keep track of the current counter state and will keep track of how often the increase and decrease buttons have been pressed. Edit src/reducers/counter.js
:
import {INCREASE, DECREASE} from './../actions/const'
const initialState = {
count: 0,
increase: 0,
decrease: 0
};
module.exports = function(state = initialState, action) {
let nextState = Object.assign({}, state);
switch(action.type) {
case INCREASE: {
nextState.count++;
nextState.increase++;
return nextState;
} break;
case DECREASE: {
nextState.count--;
nextState.decrease++;
return nextState;
} break;
default: {
return state;
}
}
}
First of all we prepare our counter component, it consists of a button to increase and decrease the counter and a place to show the current count in src/components/CounterComponent.js
, lets add that component to our main component so we can see the changes live. Edit src/components/Main.js
to render our counter component:
require('normalize.css');
require('styles/App.css');
import CounterComponent from './CounterComponent';
import React from 'react';
let yeomanImage = require('../images/yeoman.png');
class AppComponent extends React.Component {
render() {
return (
<div className="index">
<img src={yeomanImage} alt="Yeoman Generator" />
<CounterComponent
actions={this.props.actions}
count={this.props.counter.count}
/>
</div>
);
}
}
AppComponent.defaultProps = {};
export default AppComponent;
Next step is to add the UI to our counter component, edit src/components/CounterComponent.js
:
'use strict';
import React from 'react';
import { Link } from 'react-router';
require('styles//Counter.css');
class CounterComponent extends React.Component {
render() {
return (
<div className='countainer'>
<div className='counter-wrapper'>
<button onClick={this.props.actions.decrease}>-</button>
<span>{this.props.count}</span>
<button onClick={this.props.actions.increase}>+</button>
</div>
<hr />
<div className='link-wrapper'>
<Link to={'/stats'}>Show stats</Link>
</div>
</div>
);
}
}
CounterComponent.displayName = 'CounterComponent';
export default CounterComponent;
At this point the counter is in a working state, surf to the page and you can increase and decrease the counter.
Lets get the Stats Component ready, src/components/StatsComponent.js
'use strict';
import React from 'react';
require('styles//Stats.css');
class StatsComponent extends React.Component {
render() {
return (
<div className="stats-wrapper">
<div>Decreased: {this.props.counter.decrease}</div>
<div>Increased: {this.props.counter.increase}</div>
</div>
);
}
}
StatsComponent.displayName = 'StatsComponent';
export default StatsComponent;
Next step is to set up the stats container, src/containers/Stats.js
import React, {
Component,
PropTypes
} from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import StatsComponent from '../components/StatsComponent';
class Stats extends Component {
render() {
const {counter} = this.props;
return <StatsComponent counter={counter}/>;
}
}
Stats.propTypes = {
actions: PropTypes.object.isRequired,
counter: PropTypes.object.isRequired
};
function mapStateToProps(state) {
const props = { counter: state.counter };
return props;
}
function mapDispatchToProps(dispatch) {
const actions = {};
const actionMap = { actions: bindActionCreators(actions, dispatch) };
return actionMap;
}
export default connect(mapStateToProps, mapDispatchToProps)(Stats);
The last thing left to do is set up the routing, we will do this in index.js
:
import React from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import configureStore from './stores';
import App from './containers/App';
import Stats from './containers/Stats';
import { Router, Route, browserHistory } from 'react-router';
const store = configureStore();
render(
<Provider store={store}>
<Router history={browserHistory}>
<Route path="/" component={App} />
<Route path="/stats" component={Stats} />
</Router>
</Provider>,
document.getElementById('app')
);
And that's it, you can increase and decrease the counter and click the link to see the stats.
Technically the routing could also take place in the App container and we would not need the Stats container, but since react-router does not support hot reloading, warnings and errors will happen if placed anywhere else than index.js