Photo by Anita Austvika on Unsplash

React Redux starter kit

Asif Sharif

--

To understand all the moving parts of React Redux, I developed a simple counter example, using react, redux, thung, actions generators, redux store. You can also use this architecture to build any front end app using react and redux, just remove all files and code related to counter use this structure.

I assume you know basic things like react, redux, store, thungs, this article is just about how to integrate all these things. You can find all the code at

https://github.com/asifsha/react-redux-counter

To begin create a new react app by typing npm create-react-app react-redux-counter

make sure you have the latest version of nodejs, react and create-react-app.

Create a new folder components in src and then create another folder app in it.

create index.js file in app folder

import React from 'react';
import { Route } from 'react-router-dom'
import CounterPage from '../counter/index'
import About from '../about';
import Header from '../common/Header';
import {withRouter} from 'react-router';
import { connect } from 'react-redux';

const App = () => (
<div>
<header>
<Header/>
</header>

<main>
<Route exact path="/" component={CounterPage} />
<Route exact path="/about-us" component={About} />
</main>
</div>
)

function mapStatesToProps(state, ownProps) {
return {
items: state.items
};
}

const mapDispatchToProps = dispatch => ({

}
)

export default withRouter(connect(mapStatesToProps, mapDispatchToProps)(App));

https://raw.githubusercontent.com/asifsha/react-redux-counter/master/src/components/app/index.js

this will be the main component of our app.

add new folder common in src for shared/ common components, add Header.js in it

import React from 'react';
import { Navbar,Nav,NavItem } from 'react-bootstrap';
import { Link } from 'react-router-dom'


const Header = () => (
<Navbar>
<Nav>
<NavItem componentClass={Link} href='/' to='/'>Home</NavItem>
<NavItem componentClass={Link} href='/about-us' to='/about-us'>About</NavItem>
</Nav>
</Navbar>
)
export default Header;

https://raw.githubusercontent.com/asifsha/react-redux-counter/master/src/components/common/Header.js

this will be our header component for the app.

create counter folder in components folder and add index.js and counterForm.js, it can be done in one file but its a good practice to separate out presentation and container components

import React from 'react'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import * as counterActions from '../../actions/counterActions';
import CounterForm from './counterForm';

export class CounterPage extends React.Component {


render() {
return (
<CounterForm
count={this.props.count}
onIncrement={this.props.actions.increment}
onDecrement={this.props.actions.decrement}
/>
);
}
}

const mapStateToProps = state => (
{
count: state.counter.count

})


const mapDispatchToProps = dispatch => ({
actions: bindActionCreators(counterActions, dispatch)
}
)

export default connect(
mapStateToProps,
mapDispatchToProps
)(CounterPage);

https://raw.githubusercontent.com/asifsha/react-redux-counter/master/src/components/counter/index.js

import React from 'react';
import PropTypes from 'prop-types';
import { ButtonToolbar } from 'react-bootstrap';;

const CounterForm = ({ count, onIncrement, onDecrement, isIncrementing, isDecrementing }) => {
return (
<div>
<h1>Counter</h1>
<h2>Counter Value</h2>
<p>Count: {count}</p>
<ButtonToolbar>
<button
className="btn btn-primary"
bsStyle="primary"
onClick={onIncrement}>Increment </button>

<button
value={'Decrement'}
className="btn btn-success"
onClick={onDecrement}>Decrement</button>

</ButtonToolbar>
</div>
);
};

CounterForm.propTypes = {
count: PropTypes.number.isRequired,
onIncrement: PropTypes.func.isRequired,
onDecrement: PropTypes.func.isRequired
};

export default CounterForm;

https://raw.githubusercontent.com/asifsha/react-redux-counter/master/src/components/counter/counterForm.js

create a folder about in component folder and add index.js file in it

import React from 'react';

export default () => (
<div>
<h1>About Us</h1>
<p>This is the sample code to understand all the moving parts of React & Redux including Action, Action creators,Redux Thunk, Reducers </p>
</div>
)

https://raw.githubusercontent.com/asifsha/react-redux-counter/master/src/components/about/index.js

replace contents for src/index.js

import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import { ConnectedRouter } from 'react-router-redux'
import store, { history } from './store/store'
import App from './components/app'
import './index.css'


const target = document.querySelector('#root')

render(
<Provider store={store}>
<ConnectedRouter history={history}>
<div>
<App />
</div>
</ConnectedRouter>
</Provider>,
target
)

https://raw.githubusercontent.com/asifsha/react-redux-counter/master/src/index.js

now we are done with adding all the components now add actions.

create a new folder actions in src and create 2 files in it actionTypes.js, counterActions.js

export const INCREMENT = 'counter/INCREMENT'
export const DECREMENT = 'counter/DECREMENT'

https://raw.githubusercontent.com/asifsha/react-redux-counter/master/src/actions/actionTypes.js

import * as types from './actionTypes';


export const increment = () => {
return dispatch => {

dispatch({
type: types.INCREMENT
})
}
}

export const decrement = () => {
return dispatch => {

dispatch({
type: types.DECREMENT
})
}
}

https://raw.githubusercontent.com/asifsha/react-redux-counter/master/src/actions/counterActions.js

now create a folder store in src and add store.js in it

import { createStore, applyMiddleware, compose } from 'redux'
import { routerMiddleware } from 'react-router-redux'
import thunk from 'redux-thunk'
import createHistory from 'history/createBrowserHistory'
import rootReducer from '.././reducers'


export const history = createHistory()

const initialState = {}

const enhancers = []
const middleware = [
thunk,
routerMiddleware(history)
]

if (process.env.NODE_ENV === 'development') {
const devToolsExtension = window.devToolsExtension

if (typeof devToolsExtension === 'function') {
enhancers.push(devToolsExtension())
}
}

const composedEnhancers = compose(
applyMiddleware(...middleware),
...enhancers
)

const store = createStore(
rootReducer,
initialState,
composedEnhancers
)

export default store;

https://raw.githubusercontent.com/asifsha/react-redux-counter/master/src/store/store.js

this is the basic file to configure Redux store

create a new folder reducers in src folder and add three files initialState.js,

export default {
counter: {
count: 0

}
};

https://raw.githubusercontent.com/asifsha/react-redux-counter/master/src/reducers/initialState.js

I added initialstate for managing the initial state in a separate file

counterReducer.js

import * as types from '../actions/actionTypes';
import initialState from './initialState';


export default (state = initialState.counter, action) => {
switch (action.type) {

case types.INCREMENT:
return {
...state,
count: state.count + 1

};

case types.DECREMENT:
return {
...state,
count: state.count - 1

};

default:
return state;
}
}

https://raw.githubusercontent.com/asifsha/react-redux-counter/master/src/reducers/counterReducer.js

I am adding counter related reducers to its own file

index.js

import {combineReducers} from 'redux';
import counter from './counterReducer';

const rootReducer= combineReducers({
counter
});

export default rootReducer;

https://raw.githubusercontent.com/asifsha/react-redux-counter/master/src/reducers/index.js

index.js is for combining all reducers for the app, write now we only have one reducer i.e counterReducer.

You may need to install dependencies like react, redux, react-dom, history, react-bootstrap, react-redux, react-router-dom, react-router-redux, redux-thunk,

or copy the package.json file and run npm install

{
"name": "react-redux-counter",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "^16.4.1",
"react-dom": "^16.4.1",
"react-scripts": "1.1.4",
"history": "^4.7.2",
"react-bootstrap": "^0.32.1",
"react-redux": "^5.0.7",
"react-router-dom": "^4.2.2",
"react-router-redux": "^5.0.0-alpha.9",
"redux": "^3.7.2",
"redux-thunk": "^2.2.0"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
}

https://raw.githubusercontent.com/asifsha/react-redux-counter/master/package.json

I got help from these in developing this sample app.

--

--