Giter Club home page Giter Club logo

cyclejs's Introduction

Cycle.js

logo
A functional and reactive JavaScript framework for predictable code

Welcome

Question Answer
"I want to learn Cycle.js" Read the official documentation
"I have a question" Create a StackOverflow question
Or
Join the chat
Or
Open an issue
Please note all discussion-like issues are labeled discussion and immediately closed. This doesn't mean we unconsidered your discussion. We only leave actual issues open.
"I found a bug" Open an issue
"I want to help build Cycle.js" Read the Contributing guides
Then
Choose an issue marked "help wanted"

Packages

Cycle.js is comprised of many specialized packages. This repository contains all these packages, e.g., the npm package @cycle/run lives in the directory run. Below you will find a summary of each package.

Package Version Dependencies DevDependencies
@cycle/dom npm (scoped) Dependency Status devDependency Status
@cycle/history npm (scoped) Dependency Status devDependency Status
@cycle/html npm (scoped) Dependency Status devDependency Status
@cycle/http npm (scoped) Dependency Status devDependency Status
@cycle/isolate npm (scoped) Dependency Status devDependency Status
@cycle/most-run npm (scoped) Dependency Status devDependency Status
@cycle/run npm (scoped) Dependency Status devDependency Status
@cycle/rxjs-run npm (scoped) Dependency Status devDependency Status

Globally: Build Status devDependency Status

Stream libraries

The following packages are not under Cycle.js, but are important dependencies, so we display their latest versions for convenience.

Package Version
most npm version
rxjs npm version
xstream npm version

Support OpenCollective OpenCollective

Sponsors

Become a sponsor and get your logo on our README on Github with a link to your site. [Become a sponsor]

Backers

Support us with a monthly donation and help us continue our activities. [Become a backer]

Thanks

Browserstack

Browserstack for providing access to their great cross-browser testing tools.

LICENSE

The MIT License


JS.ORG ComVer

cyclejs's People

Contributors

ajmchambers avatar arnodenuijl avatar bumblehead avatar ccapndave avatar chadrien avatar chromakode avatar craigmichaelmartin avatar evenchange4 avatar frikki avatar greenkeeperio-bot avatar jvanbruegge avatar laszlokorte avatar maskinoshita avatar ntilwalli avatar ph200 avatar raquelxmoss avatar ryota-ka avatar schrepfler avatar secobarbital avatar shvaikalesh avatar staltz avatar steelfish avatar stevealee avatar stevenmathews avatar thejian avatar thiagoarrais avatar tylors avatar wbreakell avatar wclr avatar widdershin 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  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

cyclejs's Issues

'use strict' error inside Rx when running README example

First let me say thanks for the awesome work. I really enjoyed the blogpost that spawned this library as well as your intro to Rx. Huge thanks to you!

With chrome using webpack I'm hitting this bug running the example on the README. Bumping Rx to 2.3.22 fixes it. I'd submit a PR but this might require to bump cycle's version so I'll leave that up to your disgression. The tests pass.

Throw error for event stream undefined in View

Throw errors if an event stream doesn't exist, for instance in that case above where you used 'ev-click': 'clickedA' but clickedA was not defined in events: ['clickedA$', 'clickedB$'].

'use strict' causing error deep in dependency chain

This commit of error in 4.3.0 causes an error when in strict mode:

Uncaught TypeError: Cannot assign to read only property 'name' of function createError(opts) {
            var result = new Error()... <more>

The line is here.

Assigning the name property of a function is usually a no-op (non-standard though) but in strict mode it throws.

error is a dependency of virtual-dom.

This is an error that happens when trying to run the example code in the README under chrome with webpack.

I'm thinking the issue might lay with error but am unsure. I filed an issue there too. ๐Ÿ˜„

App state, route and session state (logged in etc)

I'm interested in hearing how others are solving such issues. Looking at route specifically, the proposed model/view/intent works fine enough as long as one is happy with the "current" route state only living inside the stream. In real applications however route state (and other app state) would typically also need to live somewhere else.

As an example, suppose my RouteView wants to render condititionally based on whether a user is in a logged in session state or not. How and where to keep the session state indicating successful login? It could be modelled as part of the route of course, having different routes for logged in views or not logged in views (login/registration). But then the routes would typically be less useful for supporting history apis etc (where the "/" route - home) will show different views depending on the logged in state.

It is possible to create a separate observer which would subscribe to all route and state updates of course, and persist and store the necessary "current state" in some other object (outside of the streams). From my initial reading of Rxjs it also seems there is a special Rx.BehaviourSubject which could also probably be used.

I'm hoping somebody has given this a lot more thought and/or have practical experiences to share.

Uncaught Error: VTree uses event hook `function forwardIntoStream(ev) ...

I'm experimenting with Cycle to see if I can us combineLatest to compose different portions of a vtree, unfortunately I'm getting the following error which I cannot explain.

Uncaught Error: VTree uses event hook `function forwardIntoStream(ev) { stream.onNext(ev); }` which should have been defined in `events` array of the View.

Modified hello.js example. Similar to hello.js but when the Add button is pressed the current value of the text box should get added to a list section at the bottom of the page. The original form is combined with the list of rows using combineLatest.

// ES6 - enable experiment javascript in Chrome for lambdas.

var HelloModel = Cycle.createModel(['changeName$', 'addRow$'], function (intent) {

  var lastNameChange = intent.changeName$.startWith('').replay(null, 1);
  lastNameChange.connect();

  return {
    name$: intent.changeName$.startWith(''),
    rows$: intent.addRow$
                .selectMany(x => lastNameChange.take(1))
                .doOnNext(n => console.log("last name", n))
                .scan([ ], (rs,r) => {rs.push(r); return rs})
                .startWith([])
                .do(x => console.log("list: " + x))
  };
});

var HelloView = Cycle.createView(['name$', 'rows$'], model => {

  var h = Cycle.h;

  var formSection = model.name$
  .map(name => h('div', {}, [
    h('label', 'Name:'),
    h('input', {
      'attributes': {'type': 'text'},
      'ev-input': 'inputText$'
    }),
    h('input', {
      'attributes': {'type': 'button', 'value': 'Add'},
      'ev-click': 'inputClicks$'
    }),
    h('hr'),
    h('h1', 'Hello ' + name)
    ])
   );

  var rowsSection = model.rows$.map(rows =>
    h('div', rows.map(r => h('div', r)))
  );

  return {
    vtree$: Rx.Observable.combineLatest(formSection, rowsSection, (f,r) => h('div', {}, [f,r])),
    events: ['inputText$', 'inputClicks$']
  };
});

var HelloIntent = Cycle.createIntent(['inputText$', 'inputClicks$'], function (view) {
  return {
    changeName$: view.inputText$.map(function (ev) { return ev.target.value; }),
    addRow$: view.inputClicks$
  };
});

Cycle.createRenderer('.js-container').inject(HelloView);
Cycle.circularInject(HelloModel, HelloView, HelloIntent);

Any ideas? Is this a limitation of the framework/approach? Does the whole vtree have to be created at the same time to avoid event hooks from being lost?

Writing the name of the streams three times each is too much boilerplate

For instance, the example at README.md has 'inputText$' written three times.

If you have a lot of events happening, you not only have to give unique names to them, you also need to write these names on a lot of disconnected places. It is not optimal and refactoring is too difficult.

I've been thinking about it, but I don't have a solution, so I'll just leave this issue here.

DataFlowSource

Similar to DataFlowSink and DataFlowNode, DataFlowSource should be just an annotation on an object containing Observables. That's what a source is. Has output, but no input.

Boilerplate reduction for v0.8.0

Related to #40

If a proxy is used between the injected model/view/intent then there is no need to declare an interface upfront. The flip side is that the observables hanging off the model/view/intent must be accessed through a getter function and a stringed arg.

Example from the README:

var HelloModel = Cycle.createModel(function (intent) {
  return { name$: intent.get('changeName$').startWith('') };
});

Modified data-flow-node.js:

function P() { // Proxy is ES6 reserved
  this.proxiedProps = {};
  this.get = function (streamKey) {
    if (this.proxiedProps[streamKey] === undefined) {
      this.proxiedProps[streamKey] = new Rx.Subject();
    }
    return this.proxiedProps[streamKey];
  }
}

function DataFlowNode() {
  var args = Array.prototype.slice.call(arguments);
  var definitionFn = args.pop();
  if (typeof definitionFn !== 'function') {
    throw new Error('DataFlowNode expects the definitionFn as the last argument.');
  }
  var proxies = [];
  for (var i = 0; i < definitionFn.length; i++) {
    proxies[i] = new P();
  }
  var wasInjected = false;
  var output = definitionFn.apply(this, proxies);
  checkOutputObject(output);
  copyProperties(output, this);
  this.inject = function injectIntoDataFlowNode() {
    if (wasInjected) {
      console.warn('DataFlowNode has already been injected an input.');
    }
    for (var i = 0; i < arguments.length; i++) {
      replicateAll(arguments[i], proxies[i].proxiedProps);
    }
    wasInjected = true;
  };
  this.clone = function () {
    // TODO this is broken
    return DataFlowNode.apply({}, interfaces.concat([definitionFn]));
  };
  return this;
}

ES6 Proxy would be perfect for this, but they are very much a WIP.

One idea is to default to loose mode (as above) with an opt in to strict mode (as it is now) by passing in interface string arrays. This opt-int strict checking is how React handles it with their propTypes. I found myself constantly making errors during the writing and refactoring of a toy cycle app.

I'm somewhat on the fence with the need for the .get (it is ugly in it's own way) and the stringed stream arg, but those massive interface arrays in the TodoMVC are scary. It would be awesome to couple this with the removal of the events view property as outlined in #40. That would make the README example app really nice and welcoming:

var Cycle = require('cyclejs');
var h = Cycle.h;

var HelloModel = Cycle.createModel(function (intent) {
  return { name$: intent.get('changeName$').startWith('') };
});

var HelloView = Cycle.createView(function (model) {
  return {
    vtree$: model.get('name$')
      .map(function (name) {
        return h('div', {}, [
          h('label', 'Name:'),
          h('input', {
            'attributes': {'type': 'text'},
            'ev-input': 'inputText$'
          }),
          h('h1', 'Hello ' + name)
        ]);
      })
  };
});

var HelloIntent = Cycle.createIntent(function (view) {
  return {
    changeName$: view.get('inputText$').map(function (ev) { return ev.target.value; })
  };
});

Cycle.createRenderer('.js-container').inject(HelloView);
Cycle.circularInject(HelloModel, HelloView, HelloIntent);

I'm probably missing something obvious here that is a deal-breaker. Also, the explicit interface declaration was likely a purposeful design decision. In that case please feel free to ignore my suggestion!

๐Ÿป

Template vrendering with mustache

First as strings in JS code.

Then, as files imported through require(). See browserify transformers
https://www.npmjs.org/package/brfs
https://www.npmjs.org/browse/keyword/browserify-transform
https://github.com/kurttheviking/blissify
https://github.com/featurist/html2js-browserify
https://github.com/substack/node-browserify/wiki/list-of-transforms

This is the most basic API we want:

// vtreeFromTemplate(context : Object, template : String) -> VTree
Cycle.vtreeFromTemplate({name: name}, '' +
  '<div>' +
    '<label>Name:</label>' +
    '<input type="text" ev-input="inputText$">' +
    '<hr>' +
    '<h1>{{ name }}</h1>' +
  '</div>'
);

Tests

  • BackwardFunction
  • defineModel, defineIntent
  • defineView
  • renderEvery (requires browser environment, e.g., phantomjs)

Cyclejs vs mercuryjs

It seems mercury is a more functional approach, cycle (from a glance) implements MVI but is not unidirectional (M and I interact). Clarification is welcome as well as key differences.

Implement hot reloading

I implemented react-hot-loader for React (with core being extracted into react-hot-api) and I think it should be possible to implement the same for Cycle, especially considering its this-lessness.

Would you be interested in helping out with this?

AMD

Hey @staltz! I read your post and I'm really excited to try out this MVI pattern. The app environment we're in is AMD (require.js) and I can't seem to get Cycle to return properly w/wo shims. Any thoughts on how to get it to play nice with the require.js ecosystem? Thanks!

Live vtrees (draft idea)

Wrap virtual-hyperscript h() with c() so that c() always returns an Observable of vtree, accepting Observable as children, and recursively expanding them into the parent Observable using combineLatest (because we assume children vtrees are mutually independent). We can call the Observable produced by c() as "live vtree" for now. This way we can have "components" a la React.

Example:

var h = Cycle.h;
var Rx = Cycle.Rx;

function isObservable(i) {
  return (typeof i === 'object' && typeof i.subscribe === 'function');
}

function c(tagName, properties, children) {
  var atLeastOneChildObservable = !children.every(function (i) { return !isObservable(i); });

  if (atLeastOneChildObservable) {
    // TODO make sure every item in children is an Observable

    return Rx.Observable.combineLatest(children, function() {
      var args = Array.prototype.slice.call(arguments);
      return c(tagName, properties, args);
    });
  }
  else {
    return h(tagName, properties, children);
  }
}

var x = Rx.Observable.interval(50).take(30).map(function(i) { return h('h4','x'+i); });
var y = Rx.Observable.interval(220).take(5).map(function(i) { return h('h1','Y'+i); });

var Root = {
  vtree$: c('div', {}, [x, y]) // I am a live vtree
};

Cycle.createRenderer('.js-container').inject(Root);

vtree$ might be a metastream and might need to be flattened inside a View, as a post-processing step. Live vtrees provide a way to implement "state" (from React) for Cycle.js Views. A reusable UI component (similar to React) can be implemented in Cycle simple as a function receiving properties as input, and outputting a live vtree.

Open problem: how will they work when input props change? For instance

Cycle.createView(function () {
  return {
    events: []
    vtree$: Rx.Observable.interval(1000).map(function (i) {
        return makeSomeLiveVtree(i);
        // Will the inner state observables of the live vtree get canceled
        // when this function executes?
      })
  };
});

Dependency injection for backward functions

We should aim for this API, or something better:

var Foo = Cycle.defineBackwardFunction(['bar1$', 'bar2$'], ['quux1$', 'quux2$'], function (bar, quux) {
  return {
    foo1$: Rx.Observable.merge(bar.bar1$, bar.bar2$, quux.quux1$, quux.quux2$)
  };
});

Foo.feed(Bar, Quux);

For Models, Views, Intents, we need to find a nice way of rigging this inside Cycle.link() or something else.

Pre-binding values to events based on the target element

Imagine I have various buttons with different arbitrary values, I wanna execute the same callback for them all, but I want the different values each button has being passed to the callback.

In React, I would do it like this:

React.DOM.button({
  onClick: this.handleClick.bind(this, 'foo')
}, 'FOO')

Is this possible in Cycle.js?
What is the recommended way of achieving the same end?

Immutable values and "lazy" rendering

As we know from the Clojurescript React libraries, other virtual-dom libraries (like Elm) and React itself when using Immutable.js, Mori or even plain Javascript objects, rerendering only the "branches" of the virtual DOM whose competent attributes having been changed can drastically improve speed in some cases.

I have the feeling that is possible to do this within Cycle.js easily, it would only take an immutable types library and some checks before rendering the vtrees, but I don't quite get the "everything is an observable" thing yet, so it is difficult for me to imagine it in practice.

Is it feasible? Is it a good idea? Will Cycle.js offer out-of-the-box support for it?

How does this work in a larger app?

I have basic knowledge of Rx and some experience with Flux. Though I don't quite enjoy the tone of your presentation, I find the way you compose things in Cycle very interesting and would like to learn more.

My question is how a larger application would be structured. (I guess, a port of FB Flux chat example to Cycle would be very helpful.)

For example, if there are ten components that want to "follow user", is it correct that I would:

  • Inject them all into FollowUserIntent
  • Have them all export followUserClick$ with the same name so same intent works for them?

Or would I rather have different intents, each for a specific component, but have FollowUserIntent subscribe to these intents?

Example 'simple' broken

Uncaught Error: DataFlowNode expects the definitionFn as the last argument. when cloning the BarModel.

Make virtual-hyperscript optional

As I see, virtual-hyperscript is actually only used by the framework in one line: https://github.com/staltz/cycle/blob/b92951d9067c5b1a4d296fe8892e1b7b0a905cf9/src/rendering.js#L33

If this could be removed, Cycle could be made more modular by allowing other interfaces to (virtual-dom](https://github.com/Matt-Esch/virtual-dom) (or even other implementations of virtual dom?), such as string templates (see #1), the VTree objects directly or the one I'm using here (which is the same as virtual-hyperscript, but with different syntax).

Wisp with browserify (and wispify or similar) for browser bundles

I'm trying to get a build pipeline going using wisp and browserify, and it seems browserify is unable to pick up and auto-include the required dependencies. Has anybody succeeded in building browser bundles with the resulting javascript code (after running through wisp)?

Update model with asynchronous calls

I'm having difficulty to grasp where should I add asynchronous requests that updates the model in response to events. If the returned value from the "intent handlers" must be a modification function that will be passed the current model object (as in https://github.com/staltz/todomvc-cycle/blob/d483316271c293ff3bc9dc16cce35d0a2557f74d/js/models/todos.js#L139) to modify it synchronously, how am I supposed to do asynchronous calls?

Using this as an example, instead of having the model updated by

data.valueA = (data.valueA === 'foo') ? 'FOO' : 'foo';

I want it top be updated with the result from

function getNewValue (formerValue, callback) {
  setTimeout(function () {
    var newValue = formerValue === 'foo' ? 'bar' : 'foo';
    callback(null, newValue);
  }, 1)
}

I tried to use flatMap and Rx.Observable.fromNodeCallback, but nothing worked (because I need access to the current model data before calling the asynchronous function).

This is probably a trivial problem for people experienced in FRP, I'm sorry for the trouble.

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.