Postlight spends a lot of time chatting and sharing links, and in particular we share a ton of animated GIFs throughout the course of the day. Which led us to wonder: What if we could only talk in GIF images? We’re a group of product managers, programmers, and designers, so in November 2015 we decided to see if we could build a truly GIF-focused, web-based chat app in our spare time. The result was the GIF Battle chat app that we released in January.
What is React?
Isolation is key in React. By isolating one component from another, you avoid a ton of interdependencies. This allows multiple developers to be productive on a codebase. Each developer produces isolated bits of code that are as easy to use as a regular <div> or <span>.
“User experience” (UX) is a term that should matter to anyone creating software meant to be used by humans. Developer experience is a much less commonly used term, but incredibly important. One developer can make software that is used daily by millions of people. If the developer does not prioritize user experience, he or she can make life horrible (or at least exhausting) for those millions of users. Happy, productive developers who aren’t annoyed are going to build better software. The React ecosystem prioritizes developer experience in a few very noticeable ways:
Refreshing a webpage is a thing of the past. When the developer saves a file that code is swapped live in the browser thanks to React Transform. So the code you write is always reflected in the interface on screen.
Errors Don’t Just Infest Your App
When you save a file with an error, the app doesn’t silently fail. Instead, it covers the running app with a huge red box—so you don’t miss the fact that your error has stopped the app from running. You solve problems as they crop up.
How It Feels While You Code
One of the big benefits of React is the nearly zero time wasted round-tripping between code and app. Developers can work and see the results of their changes almost instantly. Take a look at this GIF to see how it feels:
Higher Order Components
The use of higher order components in our app followed two use cases, display and data.
GIF Battle is a live, timed, battle. We need to update the UI not just on player action, but also based on the clock. Instead of implementing the logic for a timer in every component, we turned it into a higher order component:
Now we can make any part of our interface update automatically with a global clock. PlayerTimer is a component for displaying the amount of time left in a player’s turn. With a single line of code, @updateOnInterval(1), the timer goes from a static number to a ticking clock.
Components define their own data needs using a higher order component. Defining data needs alongside components means that a single file can describe everything a component needs and how it functions. A single location for code also means a single location for bugs. It meant we were able to lock down parts of our application and not worry that they might suddenly break later when a different component is on the page at the same time.
Our MessageList component handles rendering all of the messages in a battle. Here’s the entire definition of its data needs:
We also handle rendering error UI in listenToFirebase, ensuring the decorated component doesn’t have to worry about anything but the happy path.
GIF Battle was a side project. Developers cycled on and off the project regularly. Enforcing code quality without a code overlord to say, “You indented that wrong” could be difficult. Instead, we used ESLint and Stylelint.
Beyond just watching for missing semicolons, ESLint enforced best practices and style.
Stylelint ensures that our CSS is succinct and minimal, no matter which developer writes it.
We built at least four versions of GIF Battle, all within the same codebase. We didn’t throw away the code and start over each time. Using React allowed us to build our own abstractions while keeping the logic of our application isolated in components.
When we pivoted from a global, always running timer to a per-player chess timer, we were able to keep almost all of the logic we’d already written. Retaining our existing code was possible due to component isolation and higher order components.
Normally this kind of prototyping would be so costly during the development that you wouldn’t even risk it. Instead, you’d rely on iterating in the design phase. In the case of GIF Battle, that wouldn’t cut it. You can’t really test a global timer in a game in static prototypes. With React we were able to tweak and play and tweak.
Developers and Development