Giter VIP home page Giter VIP logo

delorean's Introduction

DeLorean.js

Build Status NPM version Coverage

DeLorean is a tiny Flux pattern implementation.

  • Unidirectional data flow, it makes your app logic simpler than MVC,
  • Automatically listens to data changes and keeps your data updated,
  • Makes data more consistent across your whole application,
  • It's framework agnostic, completely. There's no view framework dependency.
  • Very small, just 5K gzipped.
  • Built-in React.js integration, easy to use with Flight.js and Ractive.js and probably all others.
  • Improve your UI/data consistency using rollbacks.

Tutorial

You can learn Flux and DeLorean.js in minutes. Read the tutorial

Using with Frameworks


Install

You can install DeLorean with Bower:

bower install delorean

You can also install by NPM to use with Browserify (recommended)

npm install delorean

Usage

Hipster way:

var Flux = require('delorean').Flux;
// ...

Old-skool way:

<script src="//rawgit.com/f/delorean/master/dist/delorean.min.js"></script>
<script>
var Flux = DeLorean.Flux;
// ...
</script>

Overview

var Flux = DeLorean.Flux;
/*
 * Stores are simple data buckets which manages data.
 */
var Store = Flux.createStore({
  data: null,
  setData: function (data) {
    this.data = data;
    this.emit('change');
  },
  actions: {
    'incoming-data': 'setData'
  }
});
var store = Store;

/*
 * Dispatcher are simple action dispatchers for stores.
 * Stores handle the related action.
 */
var Dispatcher = Flux.createDispatcher({
  setData: function (data) {
    this.dispatch('incoming-data', data);
  },
  getStores: function () {
    return {increment: store};
  }
});

/*
 * Action Creators are simple controllers. They are simple functions.
 *  They talk to dispatchers. They are not required.
 */
var Actions = {
  setData: function (data) {
    Dispatcher.setData(data);
  }
};

// The data cycle.
store.onChange(function () {
  // End of data cycle.
  document.getElementById('result').innerText = store.data;
});

document.getElementById('dataChanger').onclick = function () {
  // Start data cycle:
  Actions.setData(Math.random());
};

Run this example on JSFiddle

Docs

You can read the tutorial to get started DeLorean.js with your favorite framework.

Basic Concepts

Or you can visit documents page.

Running the TodoMVC example

There is a simple TodoMVC example working with DeLorean.js

cd examples/todomvc
grunt
open index.html

Authors

Contributors

Contribution

git clone [email protected]:deloreanjs/delorean.git
cd delorean
git checkout -b your-feature-branch

After you make some changes and add your test cases to the test/spec/*Spec.js files. please run:

grunt
grunt test

When it's all OK, open a pull request.

License

MIT License

Name

The flux capacitor was the core component of Doctor Emmett Brown's DeLorean time machine

Links about DeLorean.js

delorean's People

Contributors

andreip avatar andyparisi avatar coryhouse avatar dannymidnight avatar darcyadams avatar f avatar fehmicansaglam avatar incrediblesound avatar jdlehman avatar jukkatupamaki avatar mengu avatar pavelegorkin avatar ream88 avatar rkusa avatar sboudrias avatar svdoever avatar tbranyen avatar tommoor avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

delorean's Issues

Doesn't work with Require.js

The bower distributed delorean does not work with Require.js

First problem is require('events').EventEmitter:

module.exports = requirements = {
  // DeLorean uses **Node.js native EventEmitter** for event emittion
  EventEmitter: require('events').EventEmitter,
  // and **es6-promise** for Deferred object management.
  Promise: require('es6-promise').Promise
};

But the module is defined as:

module.exports = EventEmitter

So I think in the injector it should just be require('event') right?

Second problem is in the injector:

// This library needs to work for Browserify and also standalone.
// If DeLorean is defined, it means it's called from the browser, not
// the browserify.
if (typeof DeLorean !== 'undefined') {
  for (var requirement in requirements) {
    DeLorean.Flux.define(requirement, requirements[requirement]);
  }
}

But when used in the browser with Require.js, DeLorean is undefined because:

if (typeof define === 'function' && define.amd) {
  define([], function () {
    return DeLorean;
  });
} else {
  window.DeLorean = DeLorean;
}

Should I use 'onChange' or 'storeDidChange' in my views?

Hey,

First of all, congrats for such great and simple to use/understand framework. Despite of being simple, I have a newbie question that might hide some lack of understanding of React.

In my React views, should I used 'onChange' as you show in [https://github.com/deloreanjs/delorean/blob/master/docs/tutorial.md] or 'storeDidChange' as in [https://github.com/deloreanjs/delorean/blob/master/docs/views.md#storedidchange-and-storesdidchange] ?

Thanks

Can't use delorean with requirejs

Hi guys!

Can't use delorean with requirejs, because get next error

Uncaught Error: Script error for: requirements.js
http://requirejs.org/docs/errors.html#scripterror

My code snippet

<script src="/bower_components/requirejs/require.js"></script>
<script>
    require.config({
        baseURI: "/Scripts/Places/Ratings",
        paths:
        {
            delorean: "/bower_components/delorean/dist/delorean"
        }
    });

    require(['delorean'], function(delorean) {
        console.log(delorean);
    });
</script>```

Please help!

Bug when using with require.js

When using delorean with require.js - the preferred way of using flight.js - via

var Flux = require('delorean').Flux

I get Uncaught TypeError: undefined is not a function in delorean.js:105.

Thanks for help and thanks for the great job!

Dispatcher promise only resolves after this.emit('change')

I noticed that if the store doesn't this.emit('change'), then the dispatcher never resolves it's promise.

   Dispatcher.dispatch('someAction', data).then(function() {
     console.log('dispatch resolved!');  // only fires if we emit change
   });

Is this intentional? The only reason I can think to architect it this way is to allow the Store to do some asynchronous work, which I thought is supposed to be the domain of the Action Creators?

I'd like a store to be allowed to mutate it's own data without emitting a change event. Am I crazy?

BTW, I'm not using React so feel free to ridicule me 😺

Also, I'm very new to this Flux stuff so if I'm totally missing the point please do let me know.

"You are attempting to create more than one dispatcher."

Yo @darcyadams - I've just updated the NPM package in my project and noticed I'm now getting this:
"You are attempting to create more than one dispatcher. DeLorean is intended to be used with a single dispatcher. This latest dispatcher created will overwrite any previous versions."

Seems like a bit of an anti pattern to me, and IMHO I would expect to use multiple dispatchers to effectively separate any concerns:

  • Cart Dispatcher
    • Product Listing Component
    • Product Component
    • Cart Component etc.
  • Search Dispatcher
    • Search Bar Component
    • Predictive Search Results Component etc.

A bit of a rigmarole for me, as I have to make sure this is running smoothly on everybody's machines. Will have to rollback to a previous version, and make sure we stay with that.

This seems like a deal breaker :( Could you run me through the design decisions for this?

formatScheme and variable scoping

There is a scoping issue in the formatScheme method:

Store.prototype.formatScheme = function (scheme) {
      var formattedScheme = {};
      for (var keyName in scheme) {
        var definition = scheme[keyName], defaultValue, calculatedValue;

defaultValue and calculatedValue are not reseted for the next iteration. That is, for in this example:

Flux.createStore({
  scheme: {
    a: { calculate: function() { ... } },
    b: 'foobar'
  }
})

the property b gets the calculate function from a.

Using let instead of var would solve this issue. However, let is not yet well supported. I've not made an PR, because I don't know your "style" of handling such scoping things.

FUTURE.md

Hey @darcyadams, I just started creating a file called FUTURE.md. Can you inspect it and give your opinions?

Thanks! :)

Multiple [Flux.mixins.storeListener] gives "possible EventEmitter memory leak detected. 11 listeners added"

I have multiple nested React components, and in each component I want to access state, so I have the following code:

var MyComponent = React.createClass({
    mixins: [Flux.mixins.storeListener],
    render: function () {
        var mything = this.state.stores.myStore.mything;
        :
    }
}

If I have this in too many components I get the warning:

(node) warning: possible EventEmitter memory leak detected. 11 listeners added. Use emitter.setMaxListeners() to increase limit.

Should I increase the limit, or is this not the approach I should take? I can access "global state" as well by doing:

this.stores.myStore.store.mything

but it feels better to access information in the state of the component.

Where are the states ?

In your example jsfiddle you access the stores directly {this.stores.increment.store.total}
Why not transfer the data automatically from the stores to the local state ?

The benefit will be, that it is unimportant for the view renderer from where the state data come (decoupled).

Please update NPM

Latest version on NPM is 0.8.5, the docs are related to 0.8.7

Just lost an hour of my day to this 😦

componentWillUpdate prevState

Due to react not deep cloning objects (facebook/react#2914) and the way that Delorean passes entire stores into state this makes the prevState parameter of componentWillUpdate useless. The prevState is always the current state.

thoughts?

Have scheme work for collections of items

It would be nice if the scheme validation and calculation methods also worked for a collection of items as this is typically how Flux stores are arranged. If we discuss some syntax I can probably take this on... my thinking is another attribute on the stores isCollection: true for example.

What if another mounted view listening this store?

@darcyadams

    componentWillUnmount: function () {
        for (var storeName in this.stores) {
          if (__hasOwn(this.stores, storeName)) {
            var store = this.stores[storeName];
            store.listener.removeAllListeners('change');
          }
        }
      },

What if the store is listening by other components? It'll be crashed then right?

We need to find a better way I guess.

EventEmitter memory leak detected

So, I'm running this warn:
(node) warning: possible EventEmitter memory leak detected. 11 listeners added. Use emitter.setMaxListeners() to increase limit.

I know that the origin is caused because in the ActionCreator I'm requesting some data and resolving async:

LOAD: function(seeds){
    request
      .post(config.routes.data)
      .type('form')
      .send({
        seeds: seeds
      })
      .end(function(err, res){
        Dispatcher.dispatch(constants.LOAD, res);
      });
    }

If I comment the Dispatcher.dispatch it works fine.

Since here all is clear, but if I shouldn't use this method I don't know what pattern should I follow to stop getting this warn, any idea?

Why forceUpdate instead of setState?

just wondering why you opted to use forceUpdate() here instead of the more standard React pattern of setState...

if (typeof store.store.getState === 'function') {
  state = store.store.getState();
  self.state.stores[storeName] = state;
  self.forceUpdate();
}

does setState only work on top level data? so you would have to set the .stores property here in order to trigger an update? I was always under the impression that any call to setState would trigger a render regardless of whether or not data actually changed.

[Bug] StoreListener's can't trigger but can update just fine.

In my view


import React from 'react';
import Header from './../header';
import {List} from './../listview';
import {Flux} from 'delorean';

var OverlaySearchView = React.createClass({

  mixins: [Flux.mixins.storeListener],
  watchStores: ['searchStore'],

  handleFocus(){
    console.log("focus");
    this.setState({
      searchViewActive: true
    });
  },

  handleBlur(){
    console.log("blur");
    this.setState({
      searchViewActive: false
    });
  },

  addToCart(e, element){
    cartActions.addToCart(element);
  },

  updateSearch(e){
    var query = e.target.value;
    if( query.length > 2 ){
      // Never triggers
      return this.trigger('search:query:' + this.props.searchType, query);
    }
    // Neither does this
    this.trigger('search:clear');
  },

  render(){
    var searchResults = '';
    console.log('Current results', this.getStore('searchStore'), this.__dispatcher);
    // Logs the current results and the dispatcher 

    var isActive = this.state.searchViewActive;

    if( true && isActive === true ){
      var medicines = this.getStore('searchStore');
      searchResults = (
        <div onClick={this.handleBlur}>
          <div className="search-view-overlay">
          </div>
          <div className="search-results">
            <List onClick={this.addToCart} elementRenderer={this.props.searchElementRenderer} source={medicines}></List>
          </div>
        </div>
      );
    }
    return (
      <div className={ "search-view" + (isActive?' active': '')}>
        <Header>
          <input className="search-bar form-control no-borders"  placeholder="Search" type="text"
            onFocus={this.handleFocus} onChange={this.updateSearch} />
        </Header>
        {searchResults}
      </div>
    );
  }
});


export default OverlaySearchView;

The above component is nested inside a Router.State + Delorean.Flux.mixins.storeListener view from React-Router and delorean

Am i doing something wrong here ?

EventEmitter and Promise missing when using require.js

Hi,

I am trying to load DeLorean with require.js, but the EventEmitter and Promise attributes are missing from the DeLorean object.

I am loading it like this:

require.config({
 paths: {
  "delorean": "delorean.min" 
 }  
});

require(['delorean'], function(DeLorean) {
  console.log(DeLorean);
});

The console output then looks like this:

Object {Flux: Object, Dispatcher: function, Store: function}

Without require.js and loading DeLorean through basic script tag, the attributes are there.

Is there another step i missed to get this working?

storeListenerMixin can't traverse up to find ancestor's dispatcher

__findDispatcher() relies on the React view having an attribute, _owner, to help children find the dispatcher without having to pass it all the way down. My React 13.2 views don't have this attribute. Is it a figment of legacy React? Or is there some trick I'm missing?

The mixin still works provided the dispatcher is passed down on the props of all views needing it, so there is a workaround.

Here's the code:

  // `__findDispatcher` is a private function for **React components**.
  function __findDispatcher(view) {
     // Provide a useful error message if no dispatcher is found in the chain
    if (view == null) {
      throw 'No dispatcher found. The DeLoreanJS mixin requires a "dispatcher" property to be passed to a component, or one of it\'s ancestors.';
    }
    /* `view` should be a component instance. If a component don't have
        any dispatcher, it tries to find a dispatcher from the parents. */
    if (!view.props.dispatcher) {
      return __findDispatcher(view._owner);
    }
    return view.props.dispatcher;
  }

Using React 13.2 (13.3 is out but not well described in its changelog)

Release 0.8.6 is still 0.8.5?

In the release in the first line of dist/delorean.js it says /*! delorean - v0.8.5 - 2014-11-06 */.

I'm confused. ;)

set method creates keys on store itself

Using the set method to set keys that are in the scheme it seems as though the data is set on the store object itself, wouldn't it make more sense to have some sort of data object within the store so that these properties aren't mixed in with other methods?

Maybe I'm missing something...

'new' keyword for instantiating stores?

@f the docs show creating new store instances like this: var myTodos = new TodoStore();.

However, the Flux.createStore method returns a function that returns a new store (ie a 'factory'). Using new does not seem to cause issues (at least that I have found), but wouldn't the docs be more accurate with var myTodos = TodoStore(');. Just wondering if there was a rational behind your decision to use use new here.

EventEmitter leak warning

(node) warning: possible EventEmitter memory leak detected. 11 listeners added. Use emitter.setMaxListeners() to increase limit.

The trace reported:

console.trace() events.js:148
EventEmitter.addListener events.js:148
EventEmitter.once events.js:174
(anonymous function) delorean.js:124
invokeResolver promise.js:41
Promise promise.js:28
__promiseGenerator delorean.js:123
(anonymous function) delorean.js:129
Dispatcher.waitFor delorean.js:133
Dispatcher.dispatch delorean.js:98
module.exports.Flux.createDispatcher.notify app-dispatcher.js:33
module.exports.notify notification-actions.js:6
React.createClass.notify index.js:51
boundMethod ReactCompositeComponent.js:1296
React.createClass.storeDidChange index.js:60
boundMethod ReactCompositeComponent.js:1296
(anonymous function) delorean.js:338
EventEmitter.emit events.js:99
module.exports.Flux.createStore.changeSettings settings-store.js:26
EventEmitter.emit events.js:77
Store.dispatchAction delorean.js:239
Dispatcher.dispatch delorean.js:102
module.exports.Flux.createDispatcher.changeSetting app-dispatcher.js:24
module.exports.changeSetting settings-actions.js:14
module.exports.React.createClass.onValueChange settings.js:13
boundMethod ReactCompositeComponent.js:1296
ReactCompositeComponent.createClass._handleChange ReactDOMInput.js:124
boundMethod ReactCompositeComponent.js:1296
executeDispatch EventPluginUtils.js:118
forEachEventDispatch EventPluginUtils.js:106
executeDispatchesInOrder EventPluginUtils.js:127
executeDispatchesAndRelease EventPluginHub.js:56
forEachAccumulated forEachAccumulated.js:30
EventPluginHub.processEventQueue EventPluginHub.js:270
runEventQueueInBatch ReactEventEmitterMixin.js:25
ReactEventEmitterMixin.handleTopLevel ReactEventEmitterMixin.js:51
handleTopLevelImpl ReactEventListener.js:87
Mixin.perform Transaction.js:142
ReactDefaultBatchingStrategy.batchedUpdates ReactDefaultBatchingStrategy.js:70
batchedUpdates ReactUpdates.js:114
ReactEventListener.dispatchEvent ReactEventListener.js:182

Is delorean dead?

All jsfiddle links seems to be broken and recompiling the example also causes the app to break.
Was this project abandoned?

Tutorial.md

I am following the Tutorial and i am getting an Uncaught TypeError: Cannot read property 'listener' of undefined

I thought I typed something in wrong, so I copied and pasted all the code from the tutorial and it still didn't work. Here is my code.

Add setState() Method and make getState() standard

I am proposing to make the data property an official part of the API and define a setState method as well as make getState a Store class defined method. This will allow us to implement a cleaner key-value observing system (automate the emitting of the change event) as well as other nice-to-have features like default values, computed properties, and standardized way to do data parsing.

I envision the developer would define a definitions hash like so (excuse the coffeescript, I'm just much faster with it)...

User = Flux.createStore
  definitions:
    user:
      fullName:
        default: ''
        calculate: ->
          "#{@data.user.nameFirst} #{@data.user.nameLast}"
      nameFirst:
        defualt: ''
      nameLast:
        default: ''

  setUser: (data) ->
    @set('user', data)   # Automatically emits 'change' event
    @getState()  # Returns an object with the user property, which has a calced fullName property

every store needs to define a getState method, so it seem logical to make this a standard method. This will save developers lines of code as well as give them a clean way to create client side only properties.

thoughts? If your interested, I'd be happy to take a first stab at implementing something like this.

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.