Skip to content

A basic project structure to build React JS apps using Redux.

License

Notifications You must be signed in to change notification settings

ederssouza/reactjs-redux-boilerplate

Repository files navigation

Redux boilerplate to React JS apps

Build Status Coverage Status Coverage Status

Summary

About

A basic project structure to build React JS apps using Redux.

Built using

Project structure

src
├── components
│   └── Counter
├── hooks
│   └── useCounter
├── redux
│   ├── actions
│   ├── constants
│   ├── reducers
│   ├── selectors
│   └── store
└── tests
    └── mocks

Getting started

Prerequisites

You need to install on your machine Node.js or Yarn.

Installing dependencies

npm install
# or
yarn install

Project setup

Compiles and hot-reloads for development

# start app open development mode
yarn start
# or
npm run start

Compiles and minifies for production

yarn build
# or
npm run build

Lints and fixes files

# show errors
yarn lint
# or
npm run lint

# fix errors
yarn lint:fix
# or
npm run lint:fix

Run your unit tests

# run tests
yarn test
# or
npm run test

# run tests on watch mode
yarn test:watch
# or
npm run test:watch

# run tests on coverage mode
yarn test:coverage
# or
npm run test:coverage

# run tests on coverage with watch mode
yarn test:coverage:watch
# or
npm run test:coverage:watch

How to create a reducer?

As an example, let's implement a counter component reducer. Files are also available in the repository. Follow the steps below to implement your first reducer.

  1. Create action types constants, in the constants directory:
// src/redux/constants/counter.ts

export const actionTypes = {
  COUNTER_DECREMENT: 'COUNTER_DECREMENT',
  COUNTER_INCREMENT: 'COUNTER_INCREMENT'
}
  1. Create reducer, in the reducers directory:
// src/redux/reducers/counter.ts

import { actionTypes } from '../constants/counter'

type Action = {
  type: 'COUNTER_DECREMENT' | 'COUNTER_INCREMENT'
}

const INITIAL_STATE = {
  counter: 0
}

export const counterReducers = (state = INITIAL_STATE, action: Action) => {
  switch (action.type) {
    case actionTypes.COUNTER_DECREMENT:
      return {
        ...state,
        counter: state.counter - 1
      }

    case actionTypes.COUNTER_INCREMENT:
      return {
        ...state,
        counter: state.counter + 1
      }

    default:
      return state
  }
}
  1. Import reducer on reducers main file:
// src/redux/reducers/index.ts

import { combineReducers } from 'redux'
import { counterReducers } from './counter'

export const reducers = combineReducers({
  // ...
  counterReducers
})
  1. Create action types methods, in the actions directory:
// src/redux/actions/counter.ts

import { actionTypes } from '../constants/counter'

export const actions = {
  decrement: () => ({
    type: actionTypes.COUNTER_DECREMENT
  }),

  increment: () => ({
    type: actionTypes.COUNTER_INCREMENT
  })
}
  1. Create selectors, in the selectors directory:
// src/redux/selectors/counter.ts

import { RootStateOrAny } from 'react-redux'

export const selectors = {
  getCounter: (state: RootStateOrAny) => state.counterReducers.counter
}
  1. Create a custom hook, in the hooks directory:
// src/hooks/useCounter/index.tsx

import { useSelector, useDispatch } from 'react-redux'

import { actions } from '../../redux/actions/counter'
import { selectors } from '../../redux/selectors/counter'

export function useCounter () {
  const counter = useSelector(selectors.getCounter)
  const dispatch = useDispatch()

  const handleDecrement = () => dispatch(actions.decrement())
  const handleIncrement = () => dispatch(actions.increment())

  return { counter, handleDecrement, handleIncrement }
}
  1. Import custom hook in the component:
// src/components/Counter/index.tsx

import { useCounter } from '../../hooks/useCounter'

export function Counter () {
  const { counter, handleDecrement, handleIncrement } = useCounter()

  return (
    <div>
      <h1>
        Counter: {counter}
      </h1>

      <button onClick={handleDecrement}>
        Decrement
      </button>

      <button onClick={handleIncrement}>
        Increment
      </button>
    </div>
  )
}

Contributing

Please read CONTRIBUTING.md for details on our code of conduct, and the process for submitting pull requests to us.

Versioning

We use SemVer for versioning. For the versions available, see the tags on this repository.

Authors

See also the list of contributors who participated in this project.

License

This project is licensed under the MIT License - see the LICENSE.md file for details


Develop by Eder Sampaio 👋  See my linkedin.