
With companies like Yahoo, AirBnB, Atlassian, and Github embracing
React.js, I think it’s safe to say that Facebook has set a new standard
in front-end development with this remarkable library. What drew me to React, at first, was its genius approach to rendering. What has kept me using it are things like
propTypes
, invariant
, and the belief that it’s a library’s responsibility to yell at a developer when they are doing something wrong.
While React does provide a really swell way to render views, it intentionally does not
provide a framework for control and management of data. Enter Flux: a
simple paradigm that creates easy-to follow, easy-to-debug flow of
information through your application.
It’s important to know that Flux is not a framework. Flux is more of a
design pattern than a piece of code. Flux only works when developers
hold themselves to certain conventions, which are sometimes not so
obvious. When a developer makes the inevitable mistake, we only
sometimes see the error propagate its way into an
invariant
thrown by React or the Flux dispatcher. The rest of the time, these
mistakes manifest themselves in strange and unpredictable ways.
Consider the following code from Facebook’s own page on using Flux:
var _todos = {};
/*...*/
var TodoStore = merge(EventEmitter.prototype, {
/**
* Get the entire collection of TODOs.
* @return {object}
*/
getAll: function() {
return _todos;
},
/*...*/
}
It might not be obvious how dangerous the code above is. Clearly, an attempt to make
_todos
private to the store has been made by the developer, yet the store
exposes the object through a public function. All a view needs to do to
completely break the Flux cycle is delete TodoStore.getAll().id
.
You’ve probably run in to this if you’re developing an application with
Flux and not using an Immutable library—and you probably also know it’s
now time to bring out the defensive cloning:
var TodoStore = merge(EventEmitter.prototype, {
/*...*/
getAll: function() {
return $.extend(true, {}, _todos);
},
/*...*/
}
But that doesn’t solve every problem. Imagine your view receives the result of a call to
getAll
as a prop, and then passes this prop along to the various children that need it:
data={this.props.todos[0]}>
id=this.props.todos[0].id>
{this.props.todos[0].description}
What happens when a developer makes the mistake of mutating one of
their props? It’s certainly convention to not do this, but it’s easy
enough to flub.
var todo = this.props.todo;
/*...*/
function saveTodo(todo) {
todo.id = generateUUID();
//description -> text for legacy support
todo.text = todo.description;
delete todo.description;
}
Clearly we are going to have some problems, now that this mutable,
cloned copy is being shared by multiple components. This kind of thing
is a nightmare to debug. Why wasn’t it stopped earlier? Why do our
stores even allow us to use anything other than immutable data?
At AddThis, we’re using the hand-made Flux components provided by
Facebook, but all the devs here have felt the pains I’ve enumerated
above. These are the kinds of pains a framework should solve. There are a
few Flux frameworks in the wild right now, but they all seem focused on
reducing boilerplate (a noble goal, but should it be the only one?).
Until a Flux framework can give us the rigidity that React does for
views, we won’t invest the time to migrate to one. http://www.addthis.com
No comments:
Post a Comment
Komentar