Giter VIP home page Giter VIP logo

Comments (18)

domagojk avatar domagojk commented on May 29, 2024 1

There was no reason, I just didn't thought about it :)
Great idea, I'll feature this in the next release 👍

from recycle.

m59peacemaker avatar m59peacemaker commented on May 29, 2024

Awesome! I'm also think it would be a great thing to not depend on Observable chaining.

Ideally, the developer can just import what they need.

import {filter, map, observe} from 'some-observable-library'

You would then use a compose or pipe function to chain them. This keeps from needing to load the entire library. Could recycle just state what observables it needs for internal purposes and expect those passed as standalone functions and then use them in a non-chained style?

import {filter, map, merge} from 'some-observable-library'

Recycle({
  adapters: {
    main: reactAdapter,
    observable: {filter, map, merge}
  }
})

By the way, I'd love to contribute to this. Let me know if there's something you want me to work on!

from recycle.

m59peacemaker avatar m59peacemaker commented on May 29, 2024

Here's a discussion on the most.js observable library about a related matter: cujojs/most#20

With some polish, Recycle with preact and most is dreamy.

from recycle.

domagojk avatar domagojk commented on May 29, 2024

I don't want the initialization function to be too complicated, because probably most of the people would use just a default adapter.

But, if somebody still wants to chain functions like you suggested, maybe some kind of compose function could be used?

import {compose, filter, map, merge} from 'some-observable-library'

Recycle({
  adapters: {
    main: reactAdapter,
    observable: compose({filter, map, merge})
  }
})

Well, creating a new adapter could be something you can work on if you wish :)
preact is a good idea, and probably inferno as well...

I'm currently working on helper library for testing components and didn't yet experiment with new adapters, so I suspect there will be some issues along the way...

from recycle.

m59peacemaker avatar m59peacemaker commented on May 29, 2024

I'm working on a proposal for adapters. I'm stuck on this line https://github.com/recyclejs/recycle/blob/master/src/recycle.js#L194

It seems to return a function rather than an instance of Subject, and my call to filter breaks because its API is filter(subject, predicate). Any thoughts about that?

from recycle.

m59peacemaker avatar m59peacemaker commented on May 29, 2024

I might have solved it with this:

if (!(source instanceof Subject)) {
  source = of(source)
}

I'm at 13/16 tests passing now.

from recycle.

m59peacemaker avatar m59peacemaker commented on May 29, 2024

I'm quite stuck on this one TypeError: this.predicate.call is not a function

I didn't mess with separating out react adapter from rx adapter yet. The O object is the interface my Recycle is using for observables. https://github.com/m59peacemaker/recycle/blob/adapter-refactor/src/adapter/react-rxjs.js

The application developer would import this to get the Recycle operators. https://github.com/m59peacemaker/recycle/blob/adapter-refactor/src/adapter/rx-add.js

Concerning the ugly, non-chained version https://github.com/m59peacemaker/recycle/blob/adapter-refactor/src/recycle.js#L66, that can be fixed with a pipe()/compose() function.

subscribe(
  filter(
    merge()
    () => {}
  )
)

// becomes something like

pipe(
  merge,
  filter(() => {}),
  subscribe
)

There are several things that can be perfected here, but do you agree with this direction?

from recycle.

domagojk avatar domagojk commented on May 29, 2024

Ok, I now see what you are doing. I'm sorry I didn't understand it before...
I thought you were going to do something like this:

export default {
  BaseComponent: React.Component,
  createElement: React.createElement,
  findDOMNode: ReactDOM.findDOMNode,
  render: ReactDOM.render,
  Observable: O, // custom made observable
  Subject
}

Internally, recycle would then use alredy composed version of Observable and the main recycle function (recycle.js) would not need to change.
If composed in adapter, still you would not have to load entire library but it would be composed with passed functions that you need. Actually, in a similar way it is done by default with RxJS.

But maybe I'm missing something? Is there a reson this couldn't be done in adapter?

As for tests, sadly it still not all covered yet, so even if you got 16/16 there could still be issues. Sorry about that, I'm working on it :)

from recycle.

m59peacemaker avatar m59peacemaker commented on May 29, 2024

I'm a decent example of the problem. I can implement prototype chaining, but I don't like it and I haven't done it much, so it is a bit of a hassle. There may be other developers that want to contribute, but aren't capable of chaining or understanding it. So, forcing the adapter to conform to a chaining API introduces problems and I don't see any benefit. Using a pipe function is just as nice as chaining. A library like flyd doesn't have chaining at all, so it would have to be needlessly implemented in a flyd-adapter just for Recycle to have the chaining syntax internally, rather than using pipe.

I wouldn't put additional fluff into the adapter spec just for this in Recycle's internals:

merge().filter().subscribe
// vs
pipe(merge, filter, subscribe)

from recycle.

m59peacemaker avatar m59peacemaker commented on May 29, 2024

I might have missed one of your points earlier.

I thought you were going to do something like this:

export default {
BaseComponent: React.Component,
createElement: React.createElement,
findDOMNode: ReactDOM.findDOMNode,
render: ReactDOM.render,
Observable: O, // custom made observable
Subject
}

That is basically what I did. I just renamed Observable to O for convenience. Maybe some of the confusion is because you're thinking very Rx spec whereas I suggest generalizing a little more.

Your thought seems to be:
Recycle uses Rx, so if you want it to use something else, write an adapter to translate that into Rx spec.

My thought is:
Define a generalized spec for what Recycle uses, and then write an adapter from your desired stream library into that spec. This is what cycle.js does. You could then choose a subset of Rx (just the needed operators) as Recycle's observable spec and that would technically fit my philosophy on the matter. However, I am contending that a spec that includes chaining is limiting for no benefit, so something more general and simple than Rx is ideal.

from recycle.

domagojk avatar domagojk commented on May 29, 2024

I see what you mean.
The truth is that I didn't yet use library providing an observable object that is not providing its operators like RxJS. But besides RxJS I've used only xstream.
Also, tc-39 proposal for Observable which may be added in ECMAScript is using RxJS as its implementation, so I just used that as default, because I figured map, filter and other proposed operators will be standards just as map or filter operators are standards for an Array.

That said, I'm not against your idea of implementing it like you suggested, just as long as there is no need for additional boilerplate code application developers needs to write.
For example, sources.childrenActions which is an Observable passed in component actions is usually used with operators like map and mapTo. Since you don't wish to create this kind of Observable object in adapter, does that mean we should create it in recycle main function in order to be used?

Or shoud application developer use some kind of compose operator similar to xstream like this:

actions (sources) {
  const button = sources.DOM.select('button')

  return [
    button.events('click')
      .compose(mapTo({ type: 'buttonClicked' }))
  ]
}

opposed to

button.events('click')
   .mapTo({ type: 'buttonClicked' })
}

from recycle.

m59peacemaker avatar m59peacemaker commented on May 29, 2024

Interesting. I would rather Observables not be implemented in ECMAScript, but if that is likely to happen, it is worth taking into account. I will reflect on that.

As to the usage in the application code, that is up to the adapter the developer chooses. My personal choice of adapter will likely use flyd, and so there won't be chaining. Recycle's contract to the developer would be that it provides those observables. What kind of observable would be up to the adapter.

With an Rx adapter, prototype chaining will be implemented, but mapTo won't exist on it by default, because Recycle doesn't need it. The application developer would add to Observable what they need.

// main.js
// make more operators available to the whole application
import 'rxjs/add/operator/mapTo'

But, I would suggest adding them in the files that use them for the sake of dead code elimination:

// some-component.js
import 'rxjs/add/operator/mapTo'

button.events('click')
   .mapTo({ type: 'buttonClicked' })

// if this file is removed and no other files use `mapTo`,
// `mapTo` is no longer included in the application at all. That is good!

A flyd adapter would not deal with any of that stuff. flyd streams are functors, so anything that can operate on functors will work. Ramda is a popular choice. If you look at the ramda docs, you will see it has a ton of functions. With a stream that is a functor, those functions are able to operator on the stream right out of the box. So, button.events('click') returns a stream/functor, and then the developer can do anything they want with it, like a bunch of ramda transforms with compose/pipe.

from recycle.

domagojk avatar domagojk commented on May 29, 2024

I agree with you. Current recyle API is not good enough to provide a stream library that different from RxJS. In addition to all the operators that should be passed as functions, Subject should also probably be replaced by something like makeSubject() (as in cycle.js)

This is quite a change and I would love for recycle to be that flexible.
But I won't do it right away though. Because, even though I make my way around with RxJS, I'm not an expert and I'll need help with abstracting it good enough for all stream libraries.
So, for now I must focus on making a current version stable enough. I want to first write tests for all the existing examples and try to get 100% of coverage. Then a switch to something you suggest would be easier.

To make it easier for me to understand, could you please write an example on how would you write your component (a simple click counter maybe) if flyn adapter is working?

Also, just to be clear when it comes to RxJS adaper - currently, Rx adapter is working as you described. Most of the operators do not exist by default because Recycle doesn't need them, but they can be added. Example of that is Autocomplete implementation.
The only difference is that even though they are not used in recycle itslef, I have included following operators (they help in reducing boilerplate code and are very lightweight): mapTo, do (used for debugging) and recycle specific adapters which, by the way, should probably be a part of an adapter and not in recycle itself (I will revisit this issue).

from recycle.

m59peacemaker avatar m59peacemaker commented on May 29, 2024

I've had another idea that might work as well. Recycle could use Rxjs internally (just 7kb if you only import/add what Recycle needs), and then have just a function to translate the streams back and forth. So, when sources are about to go out to the application code RxSources.map(translateFromRx) and when they are updating back to Recycle from the application code, AppSources.map(translateToRx).

By default, the translate function would just be source => source since it's already Rx :)
Could that work? It's simple, but probably hurts performance doing all the back and forth between streams, I bet. Just a thought.

from recycle.

domagojk avatar domagojk commented on May 29, 2024

I guess it could work, but it seems to me that could be done as a separate project. Again, I'm really not an expert for reactive libraries since I used just Rx and xstream...

I don't understand what do you mean by "recycle could only import/add what it needs". What exactly is currently imported from RxJS that recycle is not using (apart for mapTo operator)?

from recycle.

m59peacemaker avatar m59peacemaker commented on May 29, 2024

It doesn't. I'm sorry. I didn't mean to sound like I was saying it does. I suppose I added a detail that could have just been assumed. I was just saying, in that approach, you would just import Observable stuff directly, instead of having it passed in by an adapter. I like the simplicity there, but it's probably too costly in performance to translate the streams back and forth. Are you good at benchmarks? It would be easy to try it out. I can make a commit on my fork that is close to ready for that.

from recycle.

domagojk avatar domagojk commented on May 29, 2024

Ok, I asked because you said it would take 7kb but I'm pretty sure it's heavier then that currently...

Unfortunately no, I'm not good with benchmarks. I defenitely plan to test it out, when I find the time :)

But for your idea of "translating streams", maybe you don't even need recycle to test it out? If RxJS has its benchmark tests, you can maybe use those that are previously transformed with your library?

Neverthelss, when recycle benchmarks are ready, I'll let you know.

from recycle.

domagojk avatar domagojk commented on May 29, 2024

As you can see, there was quite some changes today.
There is no adapter anymore. I think there is really no point of connecting everything manually.

But, recycle main function didn't change much, I just imported all in index.js (which has about 40 lines of code) so it's still easy to switch libraries

from recycle.

Related Issues (20)

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.