DEV Community

Ayman Maher
Ayman Maher

Posted on

Simplest Redux

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
}  
Enter fullscreen mode Exit fullscreen mode

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')
);
Enter fullscreen mode Exit fullscreen mode
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;
  }
}
Enter fullscreen mode Exit fullscreen mode
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)))
  }
}
Enter fullscreen mode Exit fullscreen mode
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);

Enter fullscreen mode Exit fullscreen mode
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)

Enter fullscreen mode Exit fullscreen mode

Top comments (0)