- About
- Built using
- Project structure
- Getting started
- Project setup
- How to create a reducer?
- Contributing
- Versioning
- Authors
- License
A basic project structure to build React JS apps using Redux.
- React JS: JavaScript library
- Redux: A Predictable State Container for JS Apps
- TypeScript: JavaScript With Syntax For Types.
- Jest: JavaScript Testing Framework
- React Testing Library: Testing utilities
src
├── components
│ └── Counter
├── hooks
│ └── useCounter
├── redux
│ ├── actions
│ ├── constants
│ ├── reducers
│ ├── selectors
│ └── store
└── tests
└── mocks
You need to install on your machine Node.js or Yarn.
npm install
# or
yarn install
# start app open development mode
yarn start
# or
npm run start
yarn build
# or
npm run build
# show errors
yarn lint
# or
npm run lint
# fix errors
yarn lint:fix
# or
npm run lint:fix
# 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
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.
- Create action types constants, in the
constants
directory:
// src/redux/constants/counter.ts
export const actionTypes = {
COUNTER_DECREMENT: 'COUNTER_DECREMENT',
COUNTER_INCREMENT: 'COUNTER_INCREMENT'
}
- 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
}
}
- Import reducer on reducers main file:
// src/redux/reducers/index.ts
import { combineReducers } from 'redux'
import { counterReducers } from './counter'
export const reducers = combineReducers({
// ...
counterReducers
})
- 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
})
}
- 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
}
- 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 }
}
- 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>
)
}
Please read CONTRIBUTING.md for details on our code of conduct, and the process for submitting pull requests to us.
We use SemVer for versioning. For the versions available, see the tags on this repository.
See also the list of contributors who participated in this project.
This project is licensed under the MIT License - see the LICENSE.md file for details
Develop by Eder Sampaio 👋 See my linkedin.