Redux core - florypaul/ReactJS GitHub Wiki
Redux is a third party library - a state management system for cross-component or app-wide state usage. Manage state-data across multiple components and complete app.
When some data changes we use useState to react that some data has changes so update the UI for us.
-
local state - state which belongs to single component, input data, toggle button to show and hide info. useState() or useReducer() is used
-
cross-component state- state that affects multiple components - button that opens/closes overlay - useState or useReducer using prop chains or prop drilling
-
App-wide state - State that affects the entire app eg. user authentication status - requires prop chains/ prop drilling
React Content or Redux help us manage cross-component or App-wide state.
- React Context - has few potential disadvantages
- We may end up having a complex setup in case of large application, deeply nested JSX code or context provider component
- Performance can be bad- it's not good for high frequency data changes
- One central data store for your entire application
- Components subscribe to the store using useSelector(). Components never change the data in the store, they only receive changed data
- Reducer function - is responsible for changing the store data
- Actions - components dispatch/triggers actions which the reducer should perform -
- The reducer then makes the changes the data in the store then the subscribing components are notified and UI change happens
- we dispatch type and identifier names type : 'identifier'
- npm install redux react-redux
- Creating redux store in react app
- create new folder store
- create index.js file
import {createStore} from 'redux'
const counterReducer = (state = { counter: 0 }, action) = > {
if(action.type === 'increment'){
return {
counter: state.counter + 1
}
}
if(action.type === 'decrement'){
return {
counter: state.counter - 1
}
}
return state;
};
const store = createStore(counterReducer) // point the reducer function in the store
export default store;
- Connecting App to the store
- Providing the store using Provider component In main index.js
import { Provider } from 'react-redux';
import store from './store/index.js';
wrap APP with Provider component and pass our store to a store prop
<Provider store={store}>
<App/>
</Provider>
- redux data in components
- we use useSelector to access data in functional components
- we use connect method in class based components in counter.js
import { useSelector } from 'react-redux';
const counter = useSelector(state=>state.counter)
<div> Counter value {counter} </div>
- dispatching actions to change data in store
- In component we use useDispatch hook
import { useDispatch } from 'react-redux';
- In component we use useDispatch hook
const dispatch = useDispatch();
const incrementHandler = () => {
dipatch { type: 'increment' }
}
const decrementHandler = () => {
dipatch { type: 'decrement' }
}
<button onClick={incrementHandler}> Increment </button>
<button onClick={decrementHandler}> Decrement </button>
-
important connect from react-redux to access state from store
import classes from './Counter.module.css'; import React, { Component} from 'react'; import { connect } from 'react-redux'; class CounterClass extends Component { incrementCounterHandler() { this.props.increment(); } decrementCounterHandler(){ this.props.decrement(); } toggleCounterHandler(){ } render(){ return ( <main className={classes.counter}> <h1>Redux Classbased Counter</h1> <div className={classes.value}>-- { this.props.counter } --</div> <button onClick={this.incrementCounterHandler.bind(this)}>Increment Counter</button> <button onClick={this.decrementCounterHandler.bind(this)}>Decrement Counter</button> <button onClick={this.toggleCounterHandler.bind(this)}>Toggle Counter</button> </main> ); }; } const mapStateToProps = state => { return { counter: state.counter } } const mapDispatchToProps = dispatch => { return { increment : () => dispatch ({type: 'increment'}), decrement : () => dispatch ({type: 'decrement'}) } } export default connect(mapStateToProps, mapDispatchToProps)(CounterClass);
Code in store
import { legacy_createStore as createStore} from 'redux';
const initialSate = {
counter : 0,
showCounter : true
}
const reducerFunction = (state=initialSate, action) => {
switch(action.type){
case 'increment' : {
return {
counter : state.counter + 1,
showCounter : state.showCounter
}
}
case 'decrement' : {
return {
counter : state.counter - 1,
showCounter : state.showCounter
}
}
case 'toggle' : {
return {
counter: state.counter,
showCounter : !state.showCounter
}
}
default:
return state
}
/*
if(action.type === 'increment') {
return {
counter : state.counter + 1,
showCounter : state.showCounter
}
}
if(action.type === 'decrement') {
return {
counter : state.counter - 1,
showCounter : state.showCounter
}
}
if(action.type === 'toggle'){
return {
counter: state.counter,
showCounter : !state.showCounter
}
}
return state;
*/
}
const store = createStore(reducerFunction);
export default store;
-
passing user input or removing element id to the action)
-
Here we want to increase counter by 5 (can be coming from use input)
-
action payload is just and extra property which we add to the objects while dispatching
const increaseHandler = () => { dispatch({ type: 'increase', amount: 5}) }
-
in our store in the reducer function if(action.type==='increase'){ return{ counter: state.counter + action.amount } }
Potential problems:
- Avoid typo's while dispatching an action, the action type '' should be accurate
- We may have clashing identifier names, which can be avoided using JavaScript
instead of giving action.type idendifier name
if(action.type==='increase'){
* we'll assign identifier to a const variable and import this variable in the component
In the store ->
export const INCREMENT = 'increment';if(action.type === INCREMENT) {
In the component ->
import { INCREMENT } from '../store/index';
const incrementCounterHandler = () => {
dispatch({
type: INCREMENT
})
};
3. We can also splitting the reducer into smaller multiple reducers so that we don't get large super big single file
4. Best solution is to use Redux toolkit - which makes working with redux more convenient and easier