Redux can be Rough
As a part of Lambda School, I’ve spent the last month working with the organization Family Promise to build out what they describe as a “service tracker”, but more on that later. First, what is Family Promise?
Family Promise
Family Promise is an organization that helps local communities coordinate their compassion to address the root causes of family homelessness. They address the issue holistically, providing prevention services before families reach crisis, shelter and case management when they become homeless, and stabilization programs once they have secured housing to ensure they remain independent.
What help does Family Promise need?
The organization needs a way to track and visualize the services they provide besides the shelter to gain actionable insights. The long-term vision is a generalizable monitoring and evaluation (M&E) platform that meets the Family Promise’s needs and is useful to other organizations needing similar tooling.
The Product
Enter “Service Tracker”, an interactive tool that allows employees of Family Promise to manage Recipients, Programs, Service Types, and Services all on one platform. More specifically, this M&E tool permits the organization to log, track, and report on the services they are providing to families. Service Providers can easily log services, and administrators and program managers can see a dashboard of metrics for those services.
Sounds straightforward, right?
Ready, Set, Code! Or Not…
Family Promise was a build-on project for our team. This meant that a previous team of Lambda Students had already scaffolded the codebase and implemented some features. I elected to jump into the front-end repository with a few other teammates and was initially confused by the file structure.
This file structure is commonly referred to as MVC or Model-View-Controller. It doesn’t inherently exist in React as it’s derived from an object-oriented programming (OOP) pattern, but it can be implemented by separating business logic from UI logic. In general, it is understood that Controller == Container and View == Presentational.
After we understood the structure of the codebase and tested the live site, it became obvious that the previous team’s Redux implementation was not functional as the local state was not being saved within the application, and data from API calls was not appearing in the Redux store. Time to debug!
State management via Redux
A quick primer: Redux is a state management library for React. Its value is that it provides a “store” that serves as a central repository for data within the application. In order to implement Redux successfully, it takes 3 steps:
- Set up Redux store
- Set up actions
- Set up reducers
Actions are dispatched when a user interacts with a web application. Reducers are what actually target different parts of the Redux store to update. For example, an action could be getAllServicesAction which makes a GET API call to an endpoint that returns a JSON object that lists all services. This action would then dispatch “GET_ALL_SERVICE_SUCCESS” with this JSON object as its payload and head over to the servicesReducer to update the services piece of state with this new info.
Given this flow, I methodically went through the following list for each component related to services to debug why the redux store was not populating with data:
- Is this component connected to the redux store? If yes, are actions being fired off appropriately (check useEffects)?
- Is the correct endpoint being hit? If so, what does that endpoint expect based on the CRUD operation?
- How is the data organized inside of the relevant response from the endpoint? Does this match with our expectations on the front-end?
Running through this checklist, I discovered many components were not connected to the redux store, and for those that were, state was not properly mapped to props for use in the component and the serviceReducer was incorrectly assigning the payload from the endpoints to the Redux store.
What did functional Redux enable us to do?
Once we fixed the Redux implementation, we began to bring state into our forms for the Service Table. In particular, logging a new service required accurate data from the database on current Service Providers, Recipients, and Service Types. All of these fields became available as dropdowns in the form and prevented user error for mistyping names or service types.
Functional Redux allowed us to populate our Service Table as well. This table, built with Ant Design, fetched data from our /api/services_entries endpoint. Currently, the services tab populates the Services Table as expected, has filter functions on its columns, and has CRUD operations functional outside of few Ant Design bugs.
What’s next?
Outside of a few bugs, Service Tracker’s next iteration should focus on metrics. The backend team constructed a few endpoints for simple queries like the unique number of recipients and number of services performed, but the future of analytics for Family Promise will be much more contextual. For example, plotting the locations of services on a map is a good first step in that direction. And ideally, dragging the map around would generate new analytics based on the area being viewed and allow the user to dive deeper into the services behind those metrics. I foresee some challenges in UI design for the map, and edits to the codebase will have to be made so that the map is interactive in its display of metrics as users drag and click through it.
Personally, I’ll continue onto a personal project as I ramp up recruiting for full-time roles. I’m excited by real-world work and this Labs experience provided me a snapshot of what working in an AGILE team looks like. I’m hoping to take these hard skills (React/Redux, Node) with me to my next role. If you’re hiring for web developers or software engineers, please reach out!
Contact: andrew[dot]sohrabi[at]berkeley[dot]edu