omniscientjs / immstruct

Immutable data structures with history for top-to-bottom properties in component based libraries like React. Based on Immutable.js
374 stars 21 forks source link

value propagation check #72

Open dashed opened 9 years ago

dashed commented 9 years ago

I was thinking on this some more: https://github.com/omniscientjs/omniscient/issues/104#issuecomment-109815813

Rather than doing this naive check in shouldComponentUpdate, this may be done during development as an indicator that it should never occur. This can warn users that they're not really using the immutable library effectively.

API sketch:

// enable debug mode
if ('production' !== process.env.NODE_ENV) {
    immstruct.debug();
}

const struct = immstruct({foo: [1, 2]});

// adding a listener through .on(), .observe(), etc enables value propagation check.
// 
// internally, do something like this when values are propagated to listeners:
//
// if('production' !== process.env.NODE_ENV && 
//    newRoot.getIn(path) !== oldRoot.getIn(path) && 
//    Immutable.is(newRoot.getIn(path), oldRoot.getIn(path))) {
//
//   console.warn('detected node with distinct reference but have same value');
// }
struct.on('swap', _ => _);

// deliberate bad practice
struct.cursor('foo').update(function() {
     return Immutable.List.of(1, 2);
});
dashed commented 9 years ago

The only time this is good

// deliberate bad practice
struct.cursor('foo').update(function() {
     return Immutable.List.of(1, 2);
});

is during bootstrap when you're loading your models before React.render(...) and before listeners are registered:

// enable debug mode
if ('production' !== process.env.NODE_ENV) {
    immstruct.debug();
}

const struct = immstruct({foo: [1, 2]});

// load model from database, xhr, etc. 
// this is done before any listeners are subscribed.
struct.cursor('foo').update(function() {
     return Immutable.List.of(1, 2);
});

function render() {
    React.render(<Component cursor={struct.cursor()}) />);    

    // value propagation check is enabled after the first render
    struct.on('swap', render);
}
render();

// deliberate bad practice
struct.cursor('foo').update(function() {
     return Immutable.List.of(1, 2);
});