Skip to content

Instantly share code, notes, and snippets.

@Raynos
Forked from jlongster/app.js
Last active August 29, 2015 13:57

Revisions

  1. Raynos revised this gist Mar 20, 2014. 2 changed files with 42 additions and 15 deletions.
    49 changes: 34 additions & 15 deletions app.js
    Original file line number Diff line number Diff line change
    @@ -1,26 +1,44 @@
    var hash = require('observ-hash')
    var array = require('observ-array')
    var observ = require('observ')

    var dom = React.DOM;

    var App = React.createClass({
    getInitialState: function() {
    return { todos: [] };
    // create observable immutable data structure
    var state = hash({
    todos: array([])
    });

    var self = this;
    self.oState = state;

    // on data structure change call setState from
    // react to re-render
    state(function (currState) {
    // currState is plain JS object
    self.setState(currState);
    });

    // return current state
    return state();
    },

    addTodo: function() {
    this.setState(update(this.state) {
    todos.push({ value: 'hello' });
    });
    // mutable interface creates new
    // immutable data structure and emits it
    this.oState.todos.push(hash({
    value: observ('todo')
    }));
    },

    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;
    // });
    // call .get() to get item at index
    var todo = this.oState.todos.get(i);
    // again mutable interface creates new
    // immutable data structure
    todo.value.set(e.target.value);
    },

    render: function() {
    @@ -43,9 +61,10 @@ var App = React.createClass({
    });

    var TodoItem = React.createClass({
    shouldComponentUpdate: function(nextProps, nextState) {
    shouldComponentUpdate: function(nextProps) {
    // won't nextProps *always* be a new object?
    return this.props !== nextProps || this.state != nextState;
    // yep. so compare the keys inside it
    return this.props.desc !== nextProps.desc;
    },

    render: function() {
    8 changes: 8 additions & 0 deletions questions.md
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,14 @@
    Questions:

    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`?

    Answers:

    1. You can't mutate. People do because javascript, for perf you must simply not mutate. It's recommended you use some
    kind of module for mutating stuff but having immutability under the hood like observ-array & observ-hash

    2. `nextProps` is always a fresh object, so dont compare it, compare the things that can change like `desc`
  2. @jlongster jlongster revised this gist Mar 19, 2014. 1 changed file with 6 additions and 0 deletions.
    6 changes: 6 additions & 0 deletions questions.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,6 @@

    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. @jlongster jlongster created this gist Mar 19, 2014.
    61 changes: 61 additions & 0 deletions app.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,61 @@
    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);