Announcing Arch – a functional style framework for React
A little over a year ago, Red Badger teamed up with the Haller foundation to help them build an app for farmers in Africa. Like we always do at Red Badger, we looked at the new and interesting technology available at that point and decided that we’d try and build it using Facebook’s new UI library called React.
Little did we know that within a year, React would become a major part of pretty much all of our client projects and some internal ones. We fell in love with its simplicity and the power of delivering complex user interfaces quickly and with much less bugs than with any other tool before.
Naturally, we started building entire applications with React at the front end and we quickly realised we need a bit more of a pattern to manage state and data in general in the application. At about that time Flux came out and we tried our own implementation of it successfully, but something didn’t feel quite right.
We loved the functional aspects of React, like the fact React components can be pure functions of their props (which works beautifully with LiveScript). It simplifies testing and even just basic understanding of what’s happening in the application at any given time. Passing around references to stores and figuring out what state all the stores are in still felt complex, compared to the beautiful simplicity of React itself.
At that point, our React stack got quite complicated – we used LiveScript, browserify, tried a couple of different routing libraries to get the isomorphism that React makes so easy, and gradually, our answer to the question “What should I do to get the most out of React?” was getting more and more complicated. So we decided to distill our experiences and opinions into a framework that gives you all of the features we loved and a pattern to build React applications the best way we know how.
We spent the past couple of months slowly building and refining it and towards the end of April, we finally got it to a state where we felt it’s ready to open source. We call it Arch.
Arch is a front-end functional style application framework using React as a UI layer. Arch applications are isomorphic out of the box, including form processing. This means you write your application as if it was client-side only and Arch will manage the server-side portion.
This also means you don’t get any control over the code running server-side, which is a design decision. The theory behind it is that any server-side code you need to run should sit in a separate server application which you talk to over an API. This is very similar, at a high level, to Facebook’s recently announced Relay framework architecture and we agree that the server-side portion of your application should just be separate. (As with anything in Arch, with a bit of effort you can opt-out of the choices we made and run the Arch server from your own node.js/io.js application.) For development, Firebase is a good tool to give you an API based server-side persistence.
The biggest feature of Arch is the application architecture it proposes, inspired by Om and other ideas from functional (and functional reactive) programming. The architecture stands on an idea of central immutable state, describing your entire UI in a simple data structure. That data structure – a single composite value – serves as a complete model of your user interface at any point in time. Your user interface is a pure functional projection of this data structure.
Obviously, rendering a single UI state is not enough to build an application, you need to update it over time in response to the user’s actions, and you need to do it in a way that doesn’t couple your entire application to the structure of the central state. In other words, you need a way to distribute the central state to your UI components and collect the updates they make in response to user events. Om’s and Arch’s solution for this is a Cursor.
Cursor lets you dig down into a composite data structure and pass a reference to that particular path in it that can later be updated. This doesn’t require any understanding of where in the data structure the cursor is pointing to from the receiver (a UI component for example). So if you pass a cursor with a piece of state to a React component, it can safely use it if it was the entire thing. For example (written in LiveScript):
render: -> … profile-picture picture: @props.user.get ‘profilePicture’ …
When rendering a
profile-picture component we pass in a picture prop, which is a cursor we obtained by getting a
profilePicture key from a
user cursor, which was passed to us in the current component’s
props. Inside, we can then use the value:
render: -> dom.img do src: @props.picture.get ‘url’ .deref!
deref! call dereferences the cursor and gives you a plain piece of JSON data back.
Application state and user interface are not the only things you will ever need. There’s always some business logic to do: computations, data validation, sync with an API, collection of some statistics, etc. For that Arch uses state observers.
Each cursor is observable and you can register a change handler on it that can do work every time the value changes. For example talk to a backend API:
query.on-change (q) -> # make API request .then (results) -> search-results.update -> results
Whenever the query changes, this observer makes an API request and updates the
search-results cursor with the results from the response.Extracting the business logic into state observers results in easier to reuse React components and a more modular application. Changing a search provider, for example, can be as easy as swapping the relevant state observer without touching the UI components.
Arch focuses on simplicity (as opposed to complexity) and minimal solutions at every step, which sometimes means things seem harder at first. To help people get started, we provide a CLI that helps you generate a new application by simply typing
arch-cli init in your Terminal and a server that handles the isomorphic aspect of your app (
arch-cli serve). Arch tries to provide a good choice for all the decisions you make when building an application from scratch, but at the same time, not constrain you. We believe the default set of choices we made is sensible, but each decision we’ve made, you should be able to opt-out of. The aim is also to split up arch into submodules, so you can, for example, use just our cursor implementation. All those goals together should hopefully make a good flexible tool for building React applications.
Hopefully the previous paragraphs gave you enough of an overview of what Arch is, the philosophy behind it and how you would use it. Although Arch itself or parts and ideas from it are used on multiple projects at Red Badger, it’s still very early in its life and not necessarily ready for production without a bit of effort. We’ll continue working on it and post regular updates.
You can find out more about Arch at http://archjs.org (currently redirects you to Github, but we should have a website up soon). We’ll appreciate all feedback and examples of the awesome stuff you build with it and hope you’ll like it as much as we do!