Build for support large application development,developer can easily develop website, management system by this starter kit. This is not good starter kit who are looking for CMS(content management system). This Starter kit is good for who want to learn and develop with react redux from scratch.
- Project Structure
- Special Notes
- Installation and Configure
- New Module Development
- Redux Implementation for New Module
- Handle Ajax Request
- Testing with jest
- Web deployment
- Docker Implementation
|--| build
|--| config
|--| public (static file to load in this starter kit)
|----| favicon.ico
|----| index.html
|----| mainfest.json
|--| script
|----| build.js
|----| start.js
|----| test.js
|--| src
|----| asset
|------| [cssfile.scss]
|------| [Static Image Files]
|----| component
|------| [Global Component Folder]
|------| [Global Component(.js)]
|----| container
|------| [Global Smart Component Folder]
|------| [Global Smart File(.js)]
|----| layout [Main Layouts of the projects]
|----| core
|------| initializeStore.js (Initilize the main store for redux)
|------| rootReducer.js (Main reducer class for root)
|------| withReducer.js (For Lazy loading the redux store)
|----| router[Control all the routes of app]
|------| withAuthRoute.js
|------| withoutAuthRoute.js
|----| reducers[Configure the router]
|------| [Global Reducer Folder for Redux]
|------| [Global Reducer File(.js)]
|----| routes
|------| [Module Folder]
|--------| asset
|----------| [modulecssfile.scss]
|----------| [Static Image Files]
|--------| component
|----------| [Module Component Folder]
|----------| [Module Component File(.js)]
|--------| container
|----------| [Module smart component Folder]
|----------| [Module smart component File (.js)]
|--------| reducer
|----------| [Module Reducer File for Redux]
|--------| index.js (connect all the container and component for module wise redux store Lazy loading)
|------| routeSplit.js (Appling the code spliting to Each Module)
|----| shared
|-------| [Global Shared Function File]
|----| test
|-------| [React Test file(.test.js)]
|--| .eslintrc
|--| .gitignore
|--| package-lock.json
|--| package.json
|--| postcss.config.js
This starter kit support two important feature for mordern javascript development
1. Lazy loading for Redux Store
2. Module wise Code Spliting
For Lazy loading of Redux Store, I have introduced a function called withReducer()
which will load the redux on demand at runtime. for spliting the redux store we can just add the code below at every module at index.js
:
export default withReducer('homeReducer'/** key for reducer to split **/,
homeReducer/** reducer name for module **/)
(HomeContainer/** container or samrt component which create connection between redux and component)
For Module wise Code Spliting, I have introduced React Loadable
package, which will split the code at production and runtime also
Loadable({
loader: () => import('./About' /** component name or module which will be split by webpack*/),
loading: <LoadingComponent />, /** custom loading component which will be shows when component will be delay to load */
delay: 300 /** Milisecond to wait for component to load */
})
-
You can just
clone
the git repository react-admin-starter-kit -
Then run the command for:
- For npm :
npm run install
- For Yarn run :
yarn install
- For npm :
-
Application will run at local development server with port
The main feature of this starter kit is modularization. Which will provide friendly architecture for developer. To create the new module:
1. to go to -> ```routes``` folder.
2. create other necessary folders with ```index.js``` file.
Example:
```
|----| routes
|------| Contact
|--------| asset
|----------| contact.scss
|--------| component
|----------| Contact.js
|--------| container
|----------| ContactContainer.js
|--------| reducer
|----------| ContactReducer.js
|--------| index.js
```
import React from 'react'
export const Contact = (props) => {
return (
<div> This is contact page </div>
)
}
export default Contact
export const GET_CONTACT_INFO = 'GET_CONTACT_INFO'
export const SET_CONTACT_INFO = 'SET_CONTACT_INFO'
const initialState = {
contactTitle: null,
contactDetails: null
}
export function getContactInfo () {
return {
type: GET_CONTACT_INFO,
payload: {}
}
}
export function setContactInfo (data) {
return {
type: SET_CONTACT_INFO,
payload: {data}
}
}
const CONTACT_ACTION_HANDLER = {
[GET_CONTACT_INFO]: (state, action) => {
return ({...state, contactTitle: null, contactDetails: null})
},
[SET_CONTACT_INFO]: (state, action) => {
return ({...state, contactTitle: action.payload.data.contactTitle, contactDetails: action.payload.data.contactDetails})
}
}
export default function contactReducer (state = initialState, action) {
const handler = CONTACT_ACTION_HANDLER[action.type]
return handler? handler(state, action): state
}
import main component (Contact.js) and connect
function which will create connection between React component and redux reducer, And then import the ContactReducer.js
reducer to smart component ContactContainer.js
import {connect} from 'react-redux'
import {
getContactInfo,
setContactInfo
} from '../reducer/ContactReducer'
import Contact from '../component/Contact'
const loadRenderContactInfo = (dispatch) => {
dispatch(getContactInfo())
dispatch(setContactInfo({
contactTitle: "This is new contact title",
contactDetails: "This is new contact details"
}))
}
Create the mapStateToProps()
(default function for redux) which will maintain all the state for the Contact.js
component.
const mapStateToProps = (state) => ({
contactTitle: state.contactReducer.contactTitle,
contactDetails: state.contactReducer.contactDetails
})
Create the mapActionCreators()
(default function for redux) which will maintain all the functions from redux and those function are related to react component Contact.js
const mapActionCreator = (dispatch) => ({
renderContactInfo: loadRenderContactInfo(dispatch)
})
export default connect(
mapStateToProps,
mapActionCreator
)(Contact)
import ContactContainer from './container/ContactContainer'
import contactReducer from './reducer/ContactReducer'
import {withReducer} from 'core/withReducer'
export default withReducer('contactReducer', contactReducer)(ContactContainer)
Add the code spliting functionality for Contact
module by appling react loadable
to ( routes -> routeSplit.js) file
const Contact = Loadable({
loader: () => import('./Contact'),
loading: Loading,
delay: delay
})
export { Home, About, Contact }
To Add the Contact
module at Menu Bar, we should add following below object at (shared -> AppHelper.js -> getNavigationItem -> TopNav)
{id: "3", path: "/contact", label: "Contacts", withAuth: true}
There are two file include for handling the routing...
- WithAuthRoute.js : Using the Route after authentication and authorization
- WithoutAuthRoute.js : Using Before authentication and authorization
<Route exact path="/contact" component={Contact} />
import React from 'react'
export const Contact = (props) => {
return (
<div>
<h1>{props.contactTitle}</h1>
<p>{props.contactDetails}</p>
</div>
)
}
export default Contact
Handling Ajax is a important part of the for any api based application. I have introduced axios
package to handle
the Ajax request with this starter kit. which i have discuss below
import axios from 'axios'
import RequestHeaderHelper from 'shared/RequestHeaderHelper'
export const GET_POST_INFO = 'GET_POST_INFO'
export const SET_POST_INFO = 'SET_POST_INFO'
export function getPostInfo () {
return {
type: GET_POST_INFO,
payload: {}
}
}
export function setPostInfo (data) {
return {
type: SET_POST_INFO,
payload: {data}
}
}
export const getPostInfoFromApi = (data) => {
const url = `https://jsonplaceholder.typicode.com/comments?postId=${data.id}`
const request = axios.get(url, RequestHeaderHelper.jsonHeaderWithAuth())
return {type: 'GET_POST_INFO', payload: request}
}
[GET_POST_INFO]: (state, action) => {
return ({...state, posts: null })
},
[SET_POST_INFO]: (state, action) => {
return ({...state, posts: action.payload.data })
}
const loadGetPostsInfo = (data,dispatch) => {
dispatch(getPostInfoFromApi(data))
.then(resonse => {
dispatch(setPostInfo(resonse.payload.data))
})
}
const mapStateToProps = (state) => ({
contactTitle: state.contactReducer.contactTitle,
contactDetails: state.contactReducer.contactDetails,
`posts: state.contactReducer.posts`
})
For getPostsInfo
function accessible to react component we can add that function to mapActionCreators()
at ContactContainer.js
file
const mapActionCreator = (dispatch) => ({
renderContactInfo: loadRenderContactInfo(dispatch),
`getPostsInfo: (data) => loadGetPostsInfo(data,dispatch)`
})
import React from 'react'
import map from 'lodash/map'
class Contact extends React.Component {
componentDidMount() {
const {renderContactInfo, getPostsInfo} = this.props
renderContactInfo()
getPostsInfo({id: 1})
}
render() {
const {posts, contactTitle, contactDetails} = this.props
console.log(this.props)
return (
<div>
<h1>{contactTitle}</h1>
<p>{contactDetails}</p>
<ul>
{
map(posts, post =>
<li>{post.name}</li>
)
}
</ul>
</div>
)
}
}
export default Contact