Starting a React Application in 2020

2020 has been an emotional roller-coaster! One thing I am extremely excited about is a new app here at FloQast we’ve been working on, and I’d love to share some of the interesting challenges we faced with this greenfield application, specifically on the front end.

When you’re building an app from scratch, there are significant decisions that can influence the manageability of your code. And, if those decisions aren’t made early in development, you can find yourself down a massive refactoring-hole.

Stylesheets: Do We Need Them?

When the app was just a proof-of-concept, my main priority was just to make it work. So to make my life easier, I had this amazing idea for the CSS (quite awful, really):

  1. A single master stylesheet that holds all the common CSS classes
  2. A unique stylesheet for each view which can override styles on the common CSS.

I thought this would lead to DRY and reusable code, but I ended up with spaghetti.

Here’s a snippet from the Master CSS file:

.section-header button {
  background: #084683';
  padding: 7px 15px;
  margin-left: 10px;
  transition: all 0.1s ease;
}
.section-header button:hover {
  background: #0a2950;
}
.email-group button {
  font-size: 20px;
  cursor: pointer;
  color: #0f3c76;
  margin: 0px 10px;
  display: flex;
  align-items: center;
  transition: all 0.2s ease-in-out;
}
.email-group button:hover {
  color: #bb4c4c;
}

And here’s another snippet from our Requests page, which would change some styling on that button:

.requests-section .section-header button {
  padding: 10px 20px;
  margin-left: 10px;
}

Now, imagine that repeating for thousands of lines, which is what we had — just massive, life-questioning CSS files.

 

This was a nightmare! Anytime I wanted to make an update to that master stylesheet, like updating a CSS class-name, I had to be painfully aware that I did not break anything somewhere else. When we brought a new engineer to the team, it became especially apparent that we could not continue building off this paradigm.

Enter Styled-Components

Styled-components have been the perfect developer-friendly solution. This is an example of a button component which previously existed on that master stylesheet:

import React from 'react';
import styled from 'styled-components';


const Button = styled.button`
  color: #fff;
  font-size: 13px;
  background: ${props => (props.isError ? '#FF2722' : '#084683')};
  border-radius: 4px;
 box-shadow: 0 1px 3px 1px #E1E6EA;  
 padding: 7px 15px;
 width: 72px;
 text-align: center;
`;


const SquareButton = ({
  id, onClick, children, className, isError,
}) => (
  <Button
    id={id}
    className={className}
    onClick={onClick}
    isError={isError}
  >
    { children }
  </Button>
);


export default SquareButton;

What I love about styled-components is how you can encapsulate all the states and properties that influence the appearance of something like a button in a single file. This was a breath of fresh air because we really just needed to focus on shipping features.

Now, I didn’t need to worry about things like nested-classes and the organization of CSS throughout the application. Stephanie Chiu, a fellow FloQast engineer has written a great article on the benefits of this paradigm: Styled Components in React: Moving away from SCSS.

This is awesome as a developer because it becomes less about remembering where code lives and more about making flexible adjustments.

Don’t be afraid of Hooks

It’s 2020, and React-Hooks are more relevant than ever. No matter where you are there’s going to be a debate on functional versus class components. FloQast engineer, Luyao Pan has a great article on this very topic: Manage State Easier with React Hooks

Personally, I was a classist for the longest time, but I’ve hopped on the functional components train. Please keep in mind, this change didn’t happen overnight. One pain point I’ve discovered with this new architecture is the inability to easily pass refs from a parent to child component.

Naturally, you would try something like this:

import React, { Fragment, useRef } from 'react';

const ParentComponent = () => {
  const myChildRef = useRef();

  const handleOnClick = () => {
    if (myChildRef.current) {
      myChildRef.current.focus();
    }
  };

  return (
    <Fragment>
      <button onClick={handleOnClick}>
        Focus Input
      </button>
      <ChildComponent ref={myChildRef}>
        Child
      </ChildComponent>
    </Fragment>
  );
};

export default ParentComponent
and
import React from 'react';

const ChildComponent = ({ ref }) => {
  return (
    <input ref={ref}/>
  );
};

export default ChildComponent

You would be right if these were class-components, but unfortunately, we’ll get an error: Cannot pass ref to functional component

 

 

That’s some really existential stuff right there. Like, why can’t I just access methods that are only exposed on the child component? Errors like this and the lack of familiarity with the new paradigm can really discourage developers from adoption. Thankfully, the devs at Facebook have a solution for us. Introducing forward-refs, a reminder that there’s still good in the world.

import React, { forwardRef } from 'react';

const ChildComponent = forwardRef((props, ref) => {
  return (
    <input ref={ref}/>
  )
});

That’s it — no more errors! It’s a very simple and elegant solution to a common problem you would face when using hooks. Keep in mind: The internet is your friend and React has documentation on literally everything. Hooks and functional components by design are here to help us create reusable code.

Some parting words

There are huge advantages to writing an application from the ground-up. You can really influence the codebase and promote long-term strategies. So remember to be decisive with things like your CSS paradigm and your component strategy. They play integral roles in your application’s livelihood. With that said, things rarely come out perfectly the first time they are implemented. The early stages of engineering are really no different than when you’re live in production, it’s all about trial & error. Figure out what’s best for your team. Getting to these topics early will help you avoid gigantic refactors and allow you to focus on feature development.

Christopher Ngo

Chris is a Software Engineer. He tries his best to write informative and tasteful articles on his projects. English is his first language yet there is much to be desired.



Back to Blog