Daniel Deutsch
Jun 30, 2017 · 5 min read

“Everything is practice.”

— Pele


Motivation for this article

Another small application to understand Redux and React. It feels like it’s the 100th app trying to grasp Redux. But 1 month without Redux and you start at basically nothing again. I am like: “Yeah I have heard about that” — and that’s it. Action, Action Creators, Reducers, Dispatch, blabla. Too many things to understand :D So once again ↗️

Modularizing the base

Structure the components in order to fit perfectly into a Redux application.

➡️ Codebase on Github ⬅️

  • the stopwatch component has it’s own local state is not dependent on other components
  • the stats and counter components are dependent on other components
  • the AddQuestionForm is dependent on other components and also contains logical information
  • the header and question components

Modularizing helps to

  • isolate responsibilities, which means easier testing and debugging
  • better scale the app and easier for the use of Redux
  • better organize between teams

➡️ Modularized Code on Github ⬅️

Adding Redux

Action Types

Decide which components should take part in the Redux store. -> In this application only the questions have to be made available to all components.

Find what events happen in your application for this specific state. -> In this application it is

  • changing the score
  • adding questions
  • removing questions

Reducers

Reducers are pure functions, that change state according to the action type.

The reducer function provides different switch statements on how change the state. (Make sure to never change the state itself! It should be a pure function! #immutability)

For example:

export default function Player(state = initialState, action) {
switch (action.type) {
case QuestionActionTypes.ADD_PLAYER:
return [
...state,
{
name: action.name,
score: 0,
},
];
case QuestionActionTypes.REMOVE_QUESTION:
return [...state.slice(0, action.index), ...state.sclice(action.index + 1)];
case QuestionActionTypes.UPDATE_QUESTION_SCORE:
return state.map((question, index) => {
if (index === action.index) {
return {
...question,
score: question.score + question.score,
};
}
return question;
});
default:
return state;
}
}

Actions and Action Creators

Submiting an action to Redux

  • action creators generate an action (action = an event that will result in a change in state)
  • action is dispatched to the Redux store
  • a reducer passes the action to a component and returns the new state

For example for adding a question:

export const addQuestion = name => ({
type: QuestionActionTypes.ADD_QUESTION,
name,
});

Create the Redux Store

Create a store in your index.js passing it the main reducer and wrap it around your scoreboard component in order to provide the store to the whole application.

Connect the container to the store

  • use mapStateToProps to assign the state to a prop value -> assign the state of the questions as props
  • for automatically dispatching actions, that are created use:
const {dispatch, questions} = this.props;
const addQuestion = bindActionCreators(QuestionActionCreators.addQuestion, dispatch);
const removeQuestion = bindActionCreators(QuestionActionCreators.removeQuestion, dispatch);
const updateQuestionScore = bindActionCreators(QuestionActionCreators.updateQuestionScore, dispatch);
  • update the event handlers on the components accordingly (counter, question and scoreboard components)
  • the header and stopwatch components don’t need changes, because they do not participate in the Redux cycle

Add another component in the Redux App

Now we want to display details to each question

  • add a new action type (select a question)
  • extend the reducer with a new switch case and additional state
  • add a new action creator for selecting a question
  • create a new bindActionCreator in the scoreboard component
  • update mapStateToProps with the selected question index
  • create a QuestionDetail component to display details
  • update the event handler on the question component

➡️ See the commit with the implementation of the detail component on Github ⬅️

Implement ducks

For smaller apps the ducks concept can help to develop a Redux application faster. Basically instead of keeping everything modular (actions, reducers, actionCreators), we can also keep them in one file to have a better overview.

This file looks like:

// Actions
const ADD_QUESTION = 'question/ADD_QUESTION';
const REMOVE_QUESTION = 'question/REMOVE_QUESTION';
const UPDATE_QUESTION_SCORE = 'question/UPDATE_QUESTION_SCORE';
const SELECT_QUESTION = 'question/SELECT_QUESTION';
// Reducers
const initialState = {
questions: [
{
name: 'Do you like AI?',
score: 31,
created: '00:00',
updated: '00:00',
},
{
name: 'Do you like Engineering?',
score: 20,
created: '00:00',
updated: '00:00',
},
{
name: 'How many Redux Apps?',
score: 50,
created: '00:00',
updated: '00:00',
},
],
selectedQuestionIndex: -1,
};
export default function Question(state = initialState, action) {
const date = `${new Date().getHours()}:00`;
switch (action.type) {
case ADD_QUESTION:
const addQuestionList = [
...state.questions,
{
name: action.name,
score: 0,
created: date,
},
];
return {
...state,
questions: addQuestionList,
};
case REMOVE_QUESTION:
const removeQuestionList = [
...state.questions.slice(0, action.index),
...state.questions.slice(action.index + 1),
];
return {
...state,
questions: removeQuestionList,
};
case UPDATE_QUESTION_SCORE:
const updateQuestionList = state.questions.map((question, index) => {
if (index === action.index) {
return {
...question,
score: question.score + action.score,
updated: date,
};
}
return question;
});
return {
...state,
questions: updateQuestionList,
};
case SELECT_QUESTION:
return {
...state,
selectedQuestionIndex: action.index,
};
default:
return state;
}
}
// ActionCreators
export const addQuestion = name => ({
type: ADD_QUESTION,
name,
});
export const removeQuestion = index => ({
type: REMOVE_QUESTION,
index,
});
export const updateQuestionScore = (index, score) => ({
type: UPDATE_QUESTION_SCORE,
index,
score,
});
export const selectQuestion = index => ({
type: SELECT_QUESTION,
index,
});

➡️ See the commit with the implementation of ducks on Github ⬅️

Chrome Redux DevTools

const store = createStore(
QuestionReducer,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__(),
);

The DevTools help to develop and debug your Redux app. Check out this article for more.



If you gained something from this article let me know with a comment or heart. Make sure to follow for more :)

Of All Things - Tech Progress

Articles covering entrepreneurship, tech, programming, innovation, ideas, future, success and businesses. If you want to submit your story or become a writer, send a message to dd@createdd.com

Daniel Deutsch

Written by

Aspiring Web Developer with Business Law Background. Pushing the limits to make the world a better place. Open for Projects of any kind.

Of All Things - Tech Progress

Articles covering entrepreneurship, tech, programming, innovation, ideas, future, success and businesses. If you want to submit your story or become a writer, send a message to dd@createdd.com

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade