This article is for someone who wants to implement redux without going into depth
if you're in for only the code part skip to Implementation
Redux brief
Redux is aimed to put the app's state at one accessible place for all components (single source of truth) called the store
This store have our state, the store takes the reducers to adjust in the state depending on the actions taken by an interaction from the user adding item to cart or liking a picture
Actions are objects who must have a type property
Action creators are functions that return objects or functions
reducers are clean functions who has no side effects
Middleware brief(Thunk - logger)
middleware is made to intervene after an action is triggered and before it reaches the reducer aka making a change to the state
thunk middleware is used for async actions and it gets triggered when the action creator returns a function not an object (redux-thunk npm)
logger middleware is to log the action and the state
const logger = (store) => (next) => (action) => {
console.group(action.type)
console.log('the action', action)
const result = next(action)
console.log('the new state' ,store.getState() )
console.groupEnd()
return result
}
Implementation
Three dependencies needed, the first is "react-redux", the second is "redux" and the third is "redux-thunk"
index.js
a- you take your Provider from react-redux and this will open the door to something called connect which in the end when applied will allow the consumer components consume state when passed through connect as props
b- you create the store via createStore function from redux by passing to it as a first argument your reducer
c- if multiple reducers you use combineReducers from redux
d- CreateStore can take as a second argument the middleware through the applyMiddleware function which its arguments are the used middleware
import React from 'react';
import ReactDOM from 'react-dom';
import {Provider} from 'react-redux';
import {createStore, combineReducers, applyMiddleware} from 'redux';
import thunk from 'redux-thunk'
import {firstReducer} from './reducers/firstReducer';
import {secondReducer} from './reducers/secondReducer';
import App from './components/App';
// the logger function is a middleware function
const logger = (store) => (next) => (action) => {
console.group(action.type)
console.log('the action', action)
const result = next(action)
console.log('the new state' ,store.getState() )
console.groupEnd()
return result
}
//creation of store
const store = createStore(
combineReducers({firstReducer,secondReducer,moviesReducer}),
applyMiddleware(thunk,logger)
)
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById('root')
);
Reducer
any reducer would be the same idea
state is given its initial value which in this case is an object
export const firstReducer = (state={},action) => {
switch (action.type) {
case 'ACTION_TYPE':
return {...state,value:action.payload}
default:
return state;
}
}
Actions
//action taking an argument to set a value in the state
export const actionCreator = (value) => ({
type:'ACTION_TYPE',
payload:value
})
//another action that returns a function to be handled by
//thunk for async call to get for example movies
//you would create an action for loading and then another to
//set the movies
export const getMovies = () => {
return (dispatch) => {
dispatch(loadingMovies())
return fetch('api')
.then((res)=> res.json())
.then((res)=>dispatch(setMovies(res)))
}
}
Component A that creates the call
import React from 'react';
import {connect} from 'react-redux';
import {getMovies} from '../../actions/movies'
class ComponentA extends React.Component{
componentDidMount() {
this.props.movies()
}
render(){
return(
<div>
<p> i'm Component A let get those movies </p>
</div>
)
}
}
const mapDispatchToProps = (dispatch) => ({
movies: ()=> dispatch(getMovies())
})
export default connect(null,mapDispatchToProps)(ComponentA);
Component B that will display movies once returned
import React from 'react';
import {connect} from 'react-redux';
function ComponentB ({movies,loading}){
return(
<div>
<div>
<h3>movies</h3>
<ul>
{loading
? <div>loading ...</div>
:movies.map((movie,id)=>(
<div key={id}>
<li > {movie.title} </li>
</div>
))}
</ul>
</div>
</div>
)
}
const mapStateToProps = (state) => ({
movies: state.moviesReducer.movies,
loading: state.moviesReducer.loading
})
List.defaultProps={
movies:[],
loading:Boolean
}
export default connect(mapStateToProps)(ComponentB)
Top comments (0)