The live demo of the counter app builted in react using redux is here
Redux Flow
Getting Started with Redux
Redux is a predictable state container for JavaScript apps.
It helps you write applications that behave consistently, run in different environments (client, server, and native), and are easy to test. On top of that, it provides a great developer experience, such as live code editing combined with a time traveling debugger.
You can use Redux together with React, or with any other view library. It is tiny (2kB, including dependencies), but has a large ecosystem of addons available.
Why Redux
As the requirements for JavaScript single-page applications have become increasingly complicated, our code must manage more state than ever before. This state can include server responses and cached data, as well as locally created data that has not yet been persisted to the server. UI state is also increasing in complexity, as we need to manage active routes, selected tabs, spinners, pagination controls, and so on.
Managing this ever-changing state is hard. If a model can update another model, then a view can update a model, which updates another model, and this, in turn, might cause another view to update. At some point, you no longer understand what happens in your app as you have lost control over the when, why, and how of its state. When a system is opaque and non-deterministic, it’s hard to reproduce bugs or add new features.
In React Managing a local state in every component is not easy, when ever you want to access the state in children component, you have to access through porps which itself creates a problem of props drilling as data flow downwards in React
Redux allows you to manage the state of the application via a unidirectional flow where a child component can directly access the state from the redux store instead of getting state changes from parent components.
To use Redux application we have to install redux which is available as a package on NPM
1npm install redux
Flow
- When an user interacts with application, an action is dispatched
- The particular dispatched action goes to reducers and manipulates it
- A new state will be updated on the store
- Accordingly react component updates (rerenders)
- View changes on the user application
How the flow works in the application side
when ever user interacts with the application ( React component) then it goes to action -> reducers -> store -> React component.
ACTION CREATORS:
These are exactly that—functions that create actions. It’s easy to conflate the terms “action” and “action creator”, so do your best to use the proper term. in Redux, action creators simply return an action:
1function Doincrement(){2 return {3 type: "increment"4 payload:"value"5 }6}
ACTION:
An object that contains information about how we want to change some data within our central state
1{2 type: "increment"3 payload:"value"4}
DISPATCH:
A function that takes in an action, makes copies of the action, and sends them out to the reducers.
REDUCER:
A pure function that takes in an action and some existing data, changes the data according to the type and payload of the action, and then sends the updated data to the state.
Reducers specify how the application’s state changes in response to actions sent to the store. Remember that actions only describe what happened, but don’t describe how the application’s state changes. State An object that serves as the central repository of all data from the reducers.
STORE
The Store is the object that brings them together. The store has the following responsibilities:
- Holds application state;
- Allows access to state via
getState(); - Allows state to be updated via
dispatch(action); - Registers listeners via
subscribe(listener); - Handles unregistering of listeners via the function returned by
subscribe(listener).
It’s important to note that you’ll only have a single store in a Redux application. When you want to split your data handling logic, you’ll use reducer composition instead of many stores.
It’s easy to create a store if you have a reducer. we use combineReducers() to combine several reducers into one. We will now import it, and pass it to createStore().
Usage with react
React-Redux
With React-Redux, we use some components and functions to tie React and Redux together: Store, Provider, and Connect.
STORE:
The Store contains the consolidated reducers and the state.
PROVIDER:
The Provider is a component that has a reference to the Store and provides the data from the Store to the component it wraps.
CONNECT:
Connect is a function communicates with the Provider. Whatever component we wrap with Connect, that component will be able to get changes in the Store state from the Provider.
We can configure Connect to get just the part of the data we want from the Provider. Connect passes this down as props into the wrapped components.
The flow with react-redux looks like this
- Create the Provider
- Pass it a reference to our Redux Store
- Wrap any component that needs to interact with the Store with Connect
- Connect passes down the different pieces of state and any action creators we need as props down to the wrapped component.
Example : counter app in react with redux The live demo of the counter app is here
Folder structure in our React application
1-> src2 >state3 >actions4 - index.js5 >reducers6 -index.js7 >store.js8 >components9 -counter.jsx10 >index.js11 >types.js
Lets go to the index.js
1// index.js23import React from 'react';4import { render } from 'react-dom';5import { Provider } from 'react-redux';6import store from './state/store';7import Counter from './components/Counter';89render(10<Provider store={store}>11<Counter />12</Provider>,13document.getElementById('root')14);
in types.js
1//types.js23export const INCREMENT = 'increment';4export const DECREMENT = 'decrement';5export const RESET = 'reset';6export const STEP = 'step';7export const MAX = 'max';
in actions/index.js
1// actions/index.js23import { INCREMENT, DECREMENT, RESET, STEP, MAX } from '../../types';45export function DoIncrement() {6 return { type: INCREMENT };7}89export function DoDecrement() {10 return { type: DECREMENT };11}1213export function DoReset() {14 return { type: RESET };15}1617export function DoStep(e) {18 return { type: STEP, payload: e };19}20export function DOMax(e) {21 return { type: MAX, payload: e };22}
in reducers/index.js
1//reducers/index.js23import { INCREMENT, DECREMENT, RESET, STEP, MAX } from '../../types';45let intialState = {6 count: 0,7 step: 1,8 max: 409};1011function counter(state = intialState, action) {1213 switch (action.type) {1415 case INCREMENT:1617 if (state.count < state.max) {18 return { ...state, count: state.count + state.step };19 } else {20 alert(`you can't exceed more than ${state.max}`);21 return state;22 }23 case DECREMENT:24 if (state.count > 0) {25 return { ...state, count: state.count - state.step };26 } else {27 alert("you can't go below 0");28 return state;29 }30 case RESET:31 return { ...state, count: 0 };32 case STEP:33 return { ...state, step: action.payload };34 case MAX:35 return { ...state, max: action.payload };36 default:37 return state;38 }39}40export default counter;
in store.js
1//store.js23import { createStore } from 'redux';4import counter from './reducers/index.js';5const store = createStore(counter);6export default store;
in counter.jsx
1import React from 'react';2import { connect } from 'react-redux';3import { DoIncrement,DoDecrement,DoReset,DoStep,DOMax} from '../state/actions';45class Counter extends React.Component {6 render() {7 let { count, step, max, dispatch } = this.props;8 return (9 <div className="wrapper rwrapper">10 <h1 className="counter">{`count by ${step} and max up to ${max}`}</h1>11 <div className="counterValue-div">12 <h2 className="counterValue">{count}</h2>13 </div>14 <div className="btn-wrapper1">15 <button className="inc btn" onClick={() => dispatch(DoIncrement())}>16 Increment17 </button>18 <button className="dec btn" onClick={() => dispatch(DoDecrement())}>19 Decrement{' '}20 </button>21 <button className="reset btn" onClick={() => dispatch(DoReset())}>22 Reset23 </button>24 </div>25 <p className="text">STEP</p>26 <div className="btn-wrapper2 rbtn">27 {[5, 8, 10, 12, 14, 16].map(e => (28 <button29 onClick={() => dispatch(DoStep(e))}30 className={`btn1 ${step == e ? ' active' : ''} `}>31 {e}32 </button>33 ))}34 </div>35 <p className="text">MAX</p>36 <div className="btn-wrapper2 rbtn-wrapper2">37 {[50, 100, 150, 200, 250, 300].map(e => (38 <button39 onClick={() => dispatch(DOMax(e))}40 className={`btn1 ${max == e ? ' active' : ''} `} >41 {e}42 </button>43 ))}44 </div>45 </div>46 );47 }48}4950function mapStateToProps(state) {51 return { count: state.count, step: state.step, max: state.max };5253}54export default connect(mapStateToProps)(Counter);