Skip to content

Instantly share code, notes, and snippets.

@jlongster
Last active August 29, 2015 13:57
Show Gist options
  • Save jlongster/9654059 to your computer and use it in GitHub Desktop.
Save jlongster/9654059 to your computer and use it in GitHub Desktop.
var dom = React.DOM;
var App = React.createClass({
getInitialState: function() {
return { todos: [] };
},
addTodo: function() {
this.setState(update(this.state) {
todos.push({ value: 'hello' });
});
},
updateTodo: function(i, e) {
// imperative:
var todos = this.state.todos;
todos[i].value = e.target.value;
this.setState({ todos: todos });
// functional:
// this.setState(update(this.state) {
// todos[i].value = e.target.value;
// });
},
render: function() {
return dom.div(
null,
dom.button({
onClick: this.addTodo
}, 'click'),
dom.ul(
null,
this.state.todos.map((todo, i) => {
return dom.li(null, TodoItem({
desc: todo.value,
onChange: this.updateTodo.bind(this, i)
}));
})
)
);
}
});
var TodoItem = React.createClass({
shouldComponentUpdate: function(nextProps, nextState) {
// won't nextProps *always* be a new object?
return this.props !== nextProps || this.state != nextState;
},
render: function() {
return dom.div(
null,
dom.input({ value: this.props.desc,
onChange: this.props.onChange }),
this.props.desc
)
}
});
React.renderComponent(App(), document.body);

I'm trying to understand how to leverage immutability, and have a few questions:

  1. The imperative code in updateTodo is the kind of stuff you can't guarantee people won't do, and is that the reason you have a very conservative shouldComponentUpdate by default? You say never to mutate this.state in the docs, but you assume that people are going to mutate objects within the app state?

  2. I'm having trouble figuring out how to write shouldComponentUpdate even if we update this.state functionally. Won't nextProps always be new, since render creates a new props object every time? How do we compare props and nextProps?

  3. If a subcomponent has state (like the clock example that ticks every second), that state is isolated within the component and isn't attached to the top-level app state. How does Om compose state, while still keeping it in 1 data structure that lets us leverage immutability for fast dirty checking?

  4. Relatedly, I don't understand why Om continually uses rAF if it always knows when the app state changes anyway - since with immutability you need to walk up and replace the top element, and something like setState will still be called, right?

(Yes, I could go read Om's source code and I am doing that, but it's good to hear answers from people too)

@swannodette
Copy link

  1. Om uses an abstraction called Cursors. Cursors are like a limited version of functional lenses, they provide a slice into the global application state - this preserves component modularity. Components only see what they need to and can update the global app state without having to know where that data actually resides. Cortex for React works via the same principle.

  2. We don't use setState. Om continually uses rAF because it's just more efficient - all application state changes are batched.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment