Coder Social home page Coder Social logo

react-cursor's Introduction

react-cursor

Functional state management abstraction for use with Facebook React

react-cursor is an opinionated javascript implementation of the Cursor concept first seen in Om, and inspired by functional zippers.

Cursors makes it easy for us work with deeply nested immutable values that are backed by React state. This means we can store our entire application state in a single nested immutable value, allowing completely stateless React views.

One of the React maintainers wrote:

[React is] there when you want to treat state as an implementation detail of a subcomponent. This is only because we don't have a good way of externalizing state changes, while simultaneously keeping the nature of them private.

Cursors solve this problem.

features

react-cursor offers the following benefits:

  • single mutable ref to app state
  • cursors for encapsulation and modularity
  • O(1) deep equality checks (like Om)
  • fastest possible react performance
  • Manipulate deeply nested immutable values backed by React state
  • Decouple your application state from the shape of the DOM, allowing application state to be normalized
  • Mechanically eliminates React's double setState issue.

tutorial

Given a React component with state like this:

var App = React.createClass({
    getInitialState: function () {
        return {
            "a": 10,
            "b": {
                "foo": {
                    "bar": 42,
                    "baz": ['red', 'green']
                }
            }
        };
    },
    render: function () {
        return <pre>{JSON.stringify(this.state, undefined, 2)}</pre>;
    }
});

Construct a cursor:

var Cursor = require('path/to/react-cursor').Cursor;

var cursor = Cursor.build(this) // `this` is the React component's this pointer
                                // or the return value of React.renderComponent

Cursors have refine, value and onChange:

cursor.refine('a').value            //=> 10
cursor.refine('a').onChange(11);
cursor.refine('b').refine('foo').value      //=> { 'bar': 42, 'baz': ['red', 'green'] }
cursor.refine('b').refine('foo').onChange({ 'bar': 43, 'baz': ['red', 'green'] })
cursor.refine('b', 'foo', 'baz', 1).onChange('blue')

Cursors are heavily memoized to preserve reference equality between equivalent cursors, such that we can implement React.shouldComponentUpdate trivially and O(1):

shouldComponentUpdate: function (nextProps, nextState) {
    return this.props.cursor !== nextProps.cursor;
}

Due to the nature of React, this is a critical optimization when your application grows large. react-cursor provides this optimization as a mixin which can be used like so:

var ImmutableOptimizations = require('path/to/react-cursor').ImmutableOptimizations

see ImmutableOptimizations.js.

Cursors also have pendingValue() for use in event handlers. This solves the double setState bug.

example app

Cursors make it trivial to implement a React JSON editor:

live demo

Comparisons to similar libraries

There exist several similar libraries (most notably Cortex) that tackle exactly the same problem. react-cursor has one distinguishing feature: the ability to trivially implement a correct shouldComponentUpdate. Note that to do this correctly, not only do equivalent values at equal paths need to be ===, but onChange handlers at equal paths also need to be ===. (If the path changes, the DOM event handlers may need to be updated as well, requiring a render.)

I also believe react-cursor is the only library that attempts to address React's double setState issue.

notes

value and onChange are the chosen nomenclature to directly line up with React's value/onChange convention.

Cursors are implemented in terms of React.addons.update.

react-cursor currently depends on underscore, but this will be factored out (sooner if someone asks me for it).

Please email the maintainer ([email protected]) with questions, discussion or feature requests.

Contributors

The initial prototypes of react-cursor were pair programmed by Dustin Getz and Daniel Miladinov.

License

react-cursor is governed under the MIT License.

react-cursor's People

Contributors

damassi avatar danielmiladinov avatar dustingetz avatar kassens avatar trevex avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.