I should also point out that React
clearly is not purely functional. We
also have some very imperative steps
and hooks that let you break out of the
functional paradigm. But in an ideal
world, you don’t have any other sources
of data, so everything is at the top and
just flows through—meaning everything ends up being a very pure output
of these render functions.
DS: A bit earlier, you used the term
“referential transparency” to describe
the way React renders UI. Can you explain what that means?
PH: Basically, React components
have props, parameters that can be
used to instantiate those components.
You might think of them as function
parameters. In order to say, “I want
to create a type-ahead with these options,” you can just pass in the options
list as a prop.
The idea is that if you render a component using the same props and
states, you’ll always render the same
user interface. This can get a little bit
tricky, though. For example, you can’t
read from the random-number generator because that would change the output. Still, if you handle this as a pure
function of props and state and make
sure you don’t read from anything else,
you can probably see that this is going to
make testing really fast and easy. You basically say, “I just want to make sure my
component looks this certain way when
it gets this data.” Then, since you don’t
have to take the Web-driver approach
of clicking on every single button to get
the app into the right state before double-checking to make sure you’ve got everything right... well, it becomes pretty
obvious how this makes testing a whole
lot easier—which, of course, makes debugging easier as well.
Dismantling the Barriers to Entry
The Flame Graph
Componentizing the Web
Copyright held by owners/authors.
Publication rights licensed to ACM. $15.00
React can render on the server without
booting up like a full-browser DOM. It
doesn’t work like it’s just some other
domain-specific language on top of
the DOM. Basically, React pretty much
hates the DOM and wants to live outside a browser as much as possible. I
PO: We’ve basically seen the same
thing happen with WebGL or any other
generic rendering platform. It just goes
back to the question of immediate vs.
retained mode, where you soon discover that as long as you can output something, it really doesn’t matter. You just
blow away whatever was there before.
DS: I’m also curious about the functional programming aspects of React.
In particular, I’m interested in knowing more about which specific functional principles you’ve adopted.
PH: The truth is, we’re actually a
bunch of functional programming
geeks. In part, that’s because if you
truly subscribe to the Church of Functional Programming, you can get a lot
of performance benefits for free. For
example, if your data model is serializ-able and you treat your render method
as a pure function of your properties,
you get server-side rendering and
client-side rendering for free since
both of those end up being pure functions of the same data on both sides of
the wire. That way, you can guarantee
that when your application initializes,
it will get into the same state on both
sides automatically. That can be really important if you have a very state-ful kind of object-oriented mutative
system, since then it becomes much,
much harder to synchronize those two
The other advantage has to do with
optimizing your apps. We have a hook
where you can replace React’s diff algorithm with a faster custom one. Also,
many functional programmers really
like to use immutable data structures
since that lets them quickly figure out
whether something has changed—just
another example of how you can get
free performance benefits this way.
TC: In the immutable data structures
vein, one really powerful library I’ve
heard about is David Nolen’s Om.
PH: That’s a very cool piece of tech-
nology. It’s for ClojureScript, the ver-
sion of Clojure that compiles to Java-
Script. What makes Clojure really cool
is its persistent data structures, which
basically are really fast and easy-to-
use immutable data structures.
What that means for us is that if you
have a post on Facebook and somebody likes it, that gives you a new like
event that should be reflected on the
like count appearing on that post. Normally, you would just mutate that, but
then you would have no way of detecting whether the change actually happened or not, which means you would
basically need to re-render the whole
thing and then diff it. From that diff,
you would learn that only that particular part of the UI actually changed. But
if you were using immutable persistent data structures, instead of mutating the like count, you could just copy
the story object and, within that copy,
update the like count.
Normally, that would be a very expensive way to go, but in Clojure the
copy isn’t expensive since it has a way
of doing it where it shares the pointers with all the other parts of that
data structure and then allocates new
objects only for whatever actually
changed. That’s a good example of an
abstraction that’s quite complicated
under the hood and yet manages to
present a very, very simple user interface—something that’s extremely easy
for people to reason about.
TC: I assume that could also help with
PH: Right. When everything is immutable, everything gets simpler. Om
undos and redos basically just keep
around pointers to the previous state
and the next state. When you want to
undo, you just pass the old object into
React, and it will update the whole UI
TC: The whole thing?
PO: When your state is serialized into
one object at the top level, all you do is
pass that through and re-render it—
and you’re done. With some of the Om
examples I’ve seen, it just snapshots
the state at every point and then gives
you a UI that indicates how many states
you have. Then you can just drag back
and forth on that. Or you could start doing some fancier things with the help
of trees to produce a really advanced