Technology

Eleni Chappen

What I’ve learned from a few large-scale React and Redux projects

Dec. 8, 2017

A friend of mine recently starting a new job where he’ll be working a lot in React and Redux, and asked me if I had any strategies or best practices, particularly with large-scale projects.

I wish I could tell him that I do. But honestly, every time I make a framework-specific rule, I quickly come across a situation where the best solution is to break it.

What I have come up with are a few benchmarks that guide me to making sure my React code is understandable to other developers, and to Future-Me.

1. All of my logic is tested

When I ensure that all of my logic is tested, whether it’s component/view logic or action-related logic, I naturally fall into healthier coding patterns. I extract unnecessary responsibilities from my components. I write more helper functions and utility modules. I can better determine when state should be kept locally or remotely.

This also helps me determine what packages I want to introduce to my app. For example, people often debate whether Redux is an appropriate tool for their project. The co-author of Redux has even said that for many cases, local state is just fine. In my view, if Redux helps you test your logic, then you are gaining a big advantage by using it. Since reducers are supposed to be pure functions, testing them is incredibly straightforward. Action creators can be tested in isolation outside of your components. If you use any middleware to perform asynchronous requests, these can be tested in isolation as well.

Testing view logic should not be ignored either. If testing your components becomes cumbersome, or if you’re stubbing too many functions in order to test them, that’s a good sign your component is doing too much.

2. My Redux actions tell a story

Redux Dev Tools is indispensable to me when I’m building an app, and when I’m debugging one. These tools allow you to view all of your actions in real time, rewind and replay actions, and dig into the current state for each action.

The list of action names that Redux Dev Tools gives you should tell the story of your user. They should give you a crystal clear understanding what what your user is doing at any given time. An action like SEND_API_REQUESTED is way less understandable to a new developer than an action like USER_LOG_IN_REQUESTED, because it lacks the context of the user experience. Giving your actions this context helps a lot when debugging.

Redux actions should also show you the result of any asynchronous requests you make. So if I see a USER_LOG_IN_REQUESTED in my list of actions, I should know to expect a USER_LOG_IN_SUCCEEDED or USER_LOG_IN_FAILED action shortly afterward.
Using a redux middleware like redux-saga helps me keep track of asynchronous requests and their effects. With dev tools I can clearly see the order of these requests and the effects of their responses.

3. I know how to use a React component without looking up a working example of it in the codebase

If I’m looking at a component definition, I should be able to:

  1. determine whether this component is for global use or context-specific use. Often this is achieved by defining the component within certain directories, like components/elements/forms/textInput.js.

  2. know exactly what props this component receives. This can be done by using React’s prop-types package, which now allows you to more accurately define the shape of your props. So instead of doing this:

user: PropTypes.object.isRequired  

I can do this:

user: PropTypes.shape({  
  id: PropTypes.number.isRequired,
  first_name: PropTypes.string,
  state: PropTypes.oneOf(['pending', 'active', 'archived'])
}).isRequired

I feel like I’ve only scratched the surface here, but it’s a start. Happy coding!

Eleni Chappen

What People Are Reading

Technology

11/20/17

Cross-Platform mobile development is cost-effective and faster to launch

Two years ago, if a person approached us for mobile app development, the first question would be what platform to launch on first - iOS or Android. It was almost double the cost to deploy on both and double the maintenance.

Fast forward to today, we can deploy on iOS and Android quicker before, at the same time, and with the expected native quality.

So what has changed? Technology has gotten a lot better. We particularly use React Native, an open source framework from Facebook, that allows developers to develop in a common language, Javascript, and deploy on both iOS and Android.

And it is native! Previous technologies for cross platform mobile apps would create a wrapper of a web view. Think of the older experience as using the browser on your phone for a site with a few more bells and whistles. It was close but the difference is noticeable when switching to native applications, from scrolling to the overall experience.

How does this impact everything now?

Cost is no longer double for both platforms. It can even cost less due to wide spread community support developing open source libraries.

Maintenance is a lot easier. A majority of the issues can be fixed in one code base and of the same language.

Recruitment and team knowledge is easier. Your team only need to know one language and most developers know Javascript. iOS is written in Objective C or Swift and Android is written in Java.

Reusable code for desktop web views. With React Native, we are able to share over 50% of the code with the web view, saving all of the above even more.

Stay tuned, as I’ll be going more into the technologies and other benefits.

News

10/18/17

ChangeMaker Launches!

In a world where marches and protests are making weekly headlines, people are always looking for the next cause to get behind.

But what do you do when a cause or issue you’re passionate about needs more awareness and support? How do you find people to come together? How do you organize people, activities, events, and whatever else you might need to do? And if you do find people, how do you manage all the different moving parts?

And, well, what does that have to do with us at 20spokes?

Meet ChangeMaker -- a project we recently completed and launched.

Similar to sites like Kickstarter or Indiegogo, ChangeMaker allows organizations to add a project and find fellow activists to donate to or join the cause as a volunteer. The interface provides organizations the ability to detail an issue or problem, outline a solution, and how donors or volunteers can help. When people join the project as a volunteer, they can specify their particular skillset in fields such as marketing, design, legal, or data so project managers can delegate tasks to the right people.

With funding from donations, users can work on projects for their cause by using the free website. While most project management tools have some sort of fancy, pay-to-use features, ChangeMaker is completely free to use because it is donor funded and donor maintained.

We branded, designed, and coded the ChangeMaker platform in a Rails environment. We also integrated Stripe Connect, which enables organizations to receive those donations they need to power their projects.

Putting all this together sounds like it would take a good chunk of time, right? But we kicked off this project on August 8 and launched the website this week. A little more than two months. Not too shabby, eh? Just in time for the Newfounders Conference. ChangeMaker will have a big presence at the conference with donors ready to help out organizations that have ready-to-pitch projects for its demo night. Nothing is too small or too large for ChangeMaker to help its users and organizations tackle.

Give ChangeMaker a whirl at changemaker.newfounders.us.

Technology

1/6/17

React Lessons for Newcomers

At 20spokes, developers spend a roughly equal amount of time between Ruby on Rails and React. While we enjoy working in both frameworks, they are quite different in approach, and going from a Rails way of thinking to a React way of thinking can be an adjustment.

One major way in which these frameworks are different is that Rails takes care of a lot of architectural issues that React leaves open for interpretation. Coming from a Rails background, I found the openness of React to be a bit anxiety-inducing at first, but I've come to really embrace it, because it's forced me to think more carefully than ever about how other developers would approach my code.

As a team, we've also considered what our best practices should be towards React, as we all want to make our code understandable and friendly to anyone who encounters it. To that end, below is a (growing) list of our approaches to making our React projects not only maintainable, but enjoyable to work with.

Be relentless with components

The basic building block of React is the component. To those new to React, they can best be thought of as modules.

As a developer, I start to get nervous when I see large components that perform various functions. The solution to keeping your files short and sweet is to take every opportunity to break your objects into re-useable components. Having larger components may not seem like a big deal when starting a project from scratch, but if you relentlessly component-ize you'll thank yourself as your project grows.

There are some code smells to recognize when you should create new components. If you see lots of groups of markup within a single div, those groups should probably be their own component.

If we have lots of renderXXX functions within in one component that render more markup, that's usually a code-smell that whatever is being returned from those functions should be their own component.

Make components as reusable as possible by passing dynamic data as props.

Privilege functional components over class-based ones

In many cases, it's overkill to Use React's Component class for every component you create. Not all components need access to the Lifecycle Methods or local state that Component provides. Start with stateless functional components and turn them into React Component instances as needed.

Take advantage of PropTypes

We started the practice of listing out PropTypes at the bottom of every component, so other developers can quickly reference what props are needed or optional. Oftentimes, we'd investigate what data we should expect in a component by looking up examples of that component elsewhere in the codebase. This easily can be avoided by using PropTypes, which provide a quick way to see what data is being passed, and of what type that data should be. Here's an example from our reusable Button component:

Button.propTypes = {  
  text: PropTypes.string.isRequired,
  onPress: PropTypes.func.isRequired,
  disabled: PropTypes.bool,
  icon: PropTypes.string,
}

We're pointing this out because, while Facebook already notes it as a best practice in their documentation, it's something that's easy to skip over or forget to do. But for something that's not hard to do at all, it provides a lot of value when developing and maintaining your app.

Use Lifecycle Methods with care

Despite being incredibly powerful, lifecycle methods (like ComponentDidUpdate) can cause a lot of headaches to those new to React. Be careful when updating state or props within these methods, as it may cause infinite looping.

For this reason, I prefer to place lifecycle methods at the very top of a component declaration, so I can see all of that logic together when debugging.

Check out part 2 of this series, Redux Lessons for Newcomers.