DEV Community

Cover image for Redux within Full Stack JavaScript
Oliver
Oliver

Posted on

Redux within Full Stack JavaScript

About a month ago I started the first sprint of my first ever full-stack JavaScript application. Previously I had worked with React in single-page applications, and I had built server-side applications with Node.js and Express, using EJS Templates for the view, but aside from having a theoretical understanding of the process, I had never actually experienced how the client and server connect and communicate. Enter Pocket Therabuddy, a full-stack NERD (node, express, react, database) application and mental health tool built with the intention of putting better data in the hands of users and the awareness to take control of how their actions can effect their moods in both positive and negative ways.

Pocket Therabuddy began as the capstone project for my nine month long bootcamp. The only stipulations for our capstone were that we had to follow the agile methodology throughout our planning and building process, otherwise we had complete free range over our tech stack, what we wanted to build, and how we wanted to build it. It has been a few weeks since I officially graduated, but this project is something I plan to continue for a long time. In my time as a teacher and now as a developer I have always emphasized project-centric learning because it allows you to be exposed to problems and topics you would have never thought to learn about otherwise. Which brings me to the crux of this article, one of the things I learned in building this project was the role of Redux in a full-stack JavaScript application.

Redux is in short a state management tool, but in keeping track of the state it can take charge of quite a lot of important logically processes including communicating with the server.

import { authHeader } from '../helpers/authHeader';

export const habitService = {
    addHabit,
    getHistory
}

async function addHabit(habit) {

    const requestOptions = {
        method: 'POST',
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify({habit: habit})
    }

    const response = await fetch(`${process.env.REACT_APP_API_URL}/api/habittracker/add_habit`, requestOptions);
    localStorage.setItem('habits', JSON.stringify(response));
    const res = handleResponse(response);
    return res;
}

async function getHistory(user) {
    const requestOptions = {
        method: 'GET',
        headers: authHeader()
    }

    const response = await fetch(`${process.env.REACT_APP_API_URL}/api/habittracker/${user.id}/history`, requestOptions);
    const res = handleResponse(response);
    return res;
}

This is a snippet of code with a GET request and POST request to the server. All in all pretty straight forward, the fun part is how redux handles making these requests.


function fetchHistory(id){
    return dispatch => {
        dispatch(request());

        habitService.getHistory(id).then((habits) => {
            dispatch(success(habits));

        },
        error => {
            request(failure(error.toString()));
            request(alertActions.error(error.toString()));
        })
    }

    function request() { return { type: habitConstants.HABIT_HISTORY_REQUEST }};
    function success(habits) { return { type: habitConstants.HABIT_HISTORY_SUCCESS, habits }};
    function failure(error) { return { type: habitConstants.HABIT_HISTORY_FAILURE, error }}; 
}

This is the action creator for the GET request above, this action which can be called in any react component with habitActions.getHistory(id) will dispatch the request, then call the habitService.getHistory function which is the GET request from before. If the request is successful, it will pass the JSON response from the server into dispatch(success(habits)) which can be accessed in the component as this.props.habits . On failure, it will dispatch the error.

The last part in this process is how you access your redux action creators and responses within the component. Redux has both a mapStateToProps method and a dispatchState method, though I have found personally that mapStateToProps can be used for pretty much everything.


function mapStateToProps(state) {
    const { user } = state.authentication;
    const { habits } = state.fetchHabits;
    return {
        user,
        habits
    }
}

This function here will get the currently logged in user (authentication, and fetchHabits are the names of the redux reducers that handle these states) and whichever habits are returned from the server request. This function should be located outside of your React class, either above or bellow.


componentDidMount(){        
   const { dispatch, user } = this.props;           
   dispatch(habitActions.fetchHistory(user.response));    
}

Here is the dispatch call that will trigger the action creator and service request we looked at above, which will set this.props.habits to the data returned from the server.

The last crucial but very simple part is the npm package react-redux which will give you access to the connect function

import { connect } from 'react-redux'

Then at the bottom of your component connect your redux mapStateToProps function to the name of your class Component and export it as usual.


const HabitHistory = connect(mapStateToProps)(ConnectedHabitHistory);
export default HabitHistory;

If you’d like to check out Pocket Therabuddy for yourself it is deployed here and you can find the GitHub repo here with more information about running it on your local server and upcoming features. Stay tuned for an article about d3 and using data visualization with React (another thing I learned in making Pocket Therabuddy).

— MxOliver

Top comments (0)