First of all, you need to install redux and react-redux packages to your project via npm or yarn.
You can simply install them with one line of code:
npm install redux react-redux --save
or with yarn:
yarn add redux react-redux
now back to project and create 3 files with these names:
action.js, reducer.js and store.js
open action.js file. We should implement two actions for this app. One for increment and one for decrement.
in action.js
const INCREMENT_COUNTER = 'INCREMENT_COUNTER';
const DECREMENT_COUNTER = 'DECREMENT_COUNTER';
const increment = () => ({type: INCREMENT_COUNTER});
const decrement = () => ({type: DECREMENT_COUNTER});
export {
INCREMENT_COUNTER,
DECREMENT_COUNTER,
increment,
decrement
}
actions are simple functions that dispatched from component to redux
for changing the store(state) via reducers.
so we should change reducer.js:
import {INCREMENT_COUNTER, DECREMENT_COUNTER} from "./action";
const initialState = {
counter: 0
};
const reducer = (state = initialState, action) => {
switch (action.type) {
case(INCREMENT_COUNTER):
return {
...state,
counter: state.counter + 1
};
case (DECREMENT_COUNTER):
return {
...state,
counter: state.counter - 1
};
default:
return state
}
};
export default reducer
There are 3 main principles of using redux:
1- Single source of truth. The state of your whole application is
stored in an object tree within a single store.
2- The state is read-only. The only way to change the state is to emit
an action, an object describing what happened.
3- Changes are made with pure functions.
according to second principles, we must assume that the state is immutable, and each case(in switch) must return state individually.
using ...state in the returned state means that if initialState will changing in future, these cases will work properly (in this example it's not necessary).
our functions in actions are pure(3rd principle)
and for last new file store.js:
import {createStore} from "redux";
import reducer from './reducer'
const store = createStore(reducer);
export default store;
now we should apply this store to our App component.
so open App.js file and made these changes:
in App.js:
import React, {Component} from 'react';
import CounterApp from './CounterApp'
import {Provider} from 'react-redux'
import store from './store'
class App extends Component {
render() {
return (
<Provider store={store}>
<CounterApp/>
</Provider>
);
}
}
export default App;
Provider wrapped the CounterApp component and will propagate store to App and CounterApp and all other child components.
finally, change the CounterApp.js:
import React, {Component} from 'react';
import {connect} from "react-redux";
import {increment, decrement} from "./action";
class CounterApp extends Component {
handleIncrement = () => this.props.dispatch(increment());
handleDecrement = () => this.props.dispatch(decrement());
render() {
return (
<div>
<button onClick={this.handleIncrement}>Increment</button>
<p>{this.props.counter}</p>
<button onClick={this.handleDecrement}>Decrement</button>
</div>
);
}
}
const mapStateToProps = state => {
const counter = state.counter;
return {counter}
};
export default connect(mapStateToProps)(CounterApp);
we are using increment & decrement actions to dispatch actions to redux.
the state was removed and instead of state we create a special function mapStateToProps' and useconnect` to connect the state to component props.
That's done!