Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

decouple re-frame and reagent+core.async #107

Closed
wants to merge 44 commits into from

Conversation

darwin
Copy link

@darwin darwin commented Aug 16, 2015

This rewrite was motivated by #106.

In essence re-frame provides a transducer: state, event -> state.
This transducer is able to apply algorithmic transformations on series of events
and build final state up. This allows complete decoupling of [re-frame handlers,
subscriptions and middleware logic] from [mechanisms how events are queued,
processed and how are their effects applied to app-db]. This "bare re-frame" is
implemented in frame.cljs.

For maximal flexibility bare re-frame must be pure and have no knowledge
of app-db, reagent/ratom and core.async. It must be possible to create multiple
independent instances of bare re-frame.

For convenience scaffold.cljs is re-implementing original re-frame functionality
of v0.4.1 using those new bare primitives. This is exposed as public api via
core.cljs.

App developer opts-in using default implementation by requiring re-frame.core.
In this scenario re-frame creates a single app-db (reagent's ratom) and
runs single event loop where events are dispatched and processed asynchronously
using core.async channel. A single re-frame instance is created and kept in
re-frame.core/app-frame atom. Plus developer gets access to the original
API to manipulate state of this single re-frame instance.

App developer is also free to pick/implement other means of employing bare
re-frame by not requiring re-frame.core and building her own scaffold
around bare re-frame primitives.

This rewrite was motivated by day8#106.

In essence re-frame provides a transducer: state, event -> state.
This transducer is able to apply algorithmic transformations on series of events
and build final state up. This allows complete decoupling of re-frame handlers,
subscriptions and middlewares logic from mechanisms how events are queued,
processed and how are their effects applied to app-db. This "bare re-frame" is
implemented in frame.cljs.

For maximal flexibility bare re-frame must be pure and have no special knowledge
of app-db, reagent/ratom and core.async. It must be possible to create multiple
independent instances of bare re-frame.

For convenience scaffold.cljs is re-implementing original re-frame functionality
of v0.4.1 using those new bare primitives. This is exposed as public api via
core.cljs.

App developer can opt-in using default implementation by requiring re-frame.core.
In this scenario re-frame provides a single app-db which is reagent's ratom and
runs single event loop where events are dispatched and processed via core.async
channel. A single re-frame instance is created and kept in
re-frame.core/app-frame atom. Plus developer gets access to the original
imperative API to manipulate them.

App developer is also free to pick/implement other means of employing bare
re-frame by not requiring re-frame.core directly and to build own scaffold
around bare re-frame primitives.
@darwin
Copy link
Author

darwin commented Aug 16, 2015

This PR will need more work to achieve 100% compatibility.

I wrote a few tests. I plan to write more. Also made sure simpleexample works.

Open issues are:

  1. use of legacy-subscribe
  2. missing pure handler
  3. whole undo functionality is missing

project.clj Outdated
[org.clojure/clojurescript "0.0-3211"]
(defproject re-frame "0.4.2-TRANSDUCERS"
:description "A Clojurescript MVC-like Framework For Writing SPAs Using Reagent."
:url "https://github.com/Day8/re_frame.git"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why change to _?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, that was unintentional, I was renaming a folder under tests directory and intellij was too smart, I guess. Will change it back.

@@ -189,13 +164,13 @@
(fn after-handler
[db v]
(let [new-db (handler db v)]
(f new-db v) ;; call f for side effects
(f new-db v) ;; call f for side effects
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why so much whitespace?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I have reformatted it with Intellij/Cursive, it is indenting comment like that.

Feel free to edit it. I won't be touching it that much.

darwin added a commit to darwin/plastic that referenced this pull request Aug 17, 2015
@darwin
Copy link
Author

darwin commented Aug 17, 2015

I'm happy to announce a success story with Plastic. I was able to switch to this fork and use re-frame as a library:
darwin/plastic@1e87f07

My custom scaffolds for main/worker thread routers are less than 100 LOC:
https://github.com/darwin/plastic/blob/master/cljs/src/main/plastic/main/frame.cljs
https://github.com/darwin/plastic/blob/master/cljs/src/worker/plastic/worker/frame.cljs

(let [old-db @db-atom
new-db (process-event frame old-db event)]
(if-not (identical? old-db new-db)
(reset! db-atom new-db))))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This pattern:

(if-not (identitcal? old-db new-db)
  (reset! db-atom new-db))

is appearing in quite a few places, it might be better refactor it out to a separate fn:

(defn reset-if-changed! [db-atom old-db new-db] (...))

@thenonameguy
Copy link
Contributor

LGTM

@thenonameguy
Copy link
Contributor

@danielcompton, @mike-thompson-day8 this PR has been sitting idle for a while, but would make great improvements to the code base. Can we get an estimate when this will be reviewed/merged? Having multiple re-frame instances on a single page would be really beneficial to my use case.

@danielcompton
Copy link
Contributor

@thenonameguy honestly these changes are massive (but really interesting), and I'm going to need some time to chew over them. Mike and I are both in a pretty busy phase of work at the moment and speaking for myself I don't have the time or mental capacity to review it right now. Ballpark estimate, I doubt I'd be able to look at it for a few weeks at least, and I suspect Mike is in a similar boat to me.

If you're keen to work with this in the meantime, you could always take this patch and run a forked version for a while. Your feedback on how it feels from an API perspective would also be helpful here.

I know that's not perhaps not the answer you were looking for, but I don't have a lot of time or energy to give in the very short term to help get this over the line.

@danielcompton
Copy link
Contributor

Also, Day8 have what I presume to be the largest Re-Frame codebase in existence, and we don't want to break our own apps or get stuck on an old version without having good mitigations for the points that @darwin has mentioned above. None of this is to say that this will (or won't) get merged, but we do have some other considerations to take into account as well.

@thenonameguy
Copy link
Contributor

Sure, thanks for the response. Then I'll just start using a fork as you mentioned.

@darwin
Copy link
Author

darwin commented Nov 26, 2015

For people interested in this version. I'm going maintain the fork here:
https://github.com/binaryage/pure-frame

Just released v0.1.0 as binaryage/pure-frame

@dijonkitchen
Copy link
Contributor

Any updates or should it be closed?

@darwin darwin closed this Nov 6, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants