update dependencies and fix things in views.reagent(+ .sente)

This commit is contained in:
Gered 2022-01-12 17:18:04 -05:00
parent b832409dfa
commit 17667c274a
6 changed files with 172 additions and 199 deletions

View file

@ -1,6 +1,7 @@
# views.reagent # views.reagent
[Reagent][1] plugin for the [views][2] library, providing real-time component updates to server-side changes to data. [Reagent][1] plugin for the [views][2] library, providing real-time component updates to
server-side changes to data.
[1]: https://github.com/reagent-project/reagent [1]: https://github.com/reagent-project/reagent
[2]: https://github.com/gered/views [2]: https://github.com/gered/views
@ -11,40 +12,48 @@
This library is made up of two core parts: This library is made up of two core parts:
* The actual library, views.reagent, providing core functionality. * The actual library, views.reagent, providing core functionality.
* A client/server communications plugin library which provides the glue code between whatever underlying client/server library you're using (e.g. [Sente][3] or [clj-browserchannel][4]) and views.reagent. * A client/server communications plugin library which provides the glue code between whatever
underlying client/server library you're using (most likely [Sente][3]) and views.reagent.
[3]: https://github.com/ptaoussanis/sente [3]: https://github.com/ptaoussanis/sente
[4]: https://github.com/gered/clj-browserchannel
To use views.reagent in your application, you need to add both the main library and one client/server communications plugin library as dependencies. See their respective pages linked to below for more information on doing this. To use views.reagent in your application, you need to add both the main library and one
client/server communications plugin library as dependencies. See their respective pages linked
to below for more information on doing this.
### Main Library Documentation ### Main Library Documentation
[See here for full documentation.][5] [See here for full documentation.][4]
[5]: https://github.com/gered/views.reagent/tree/master/views.reagent [4]: https://github.com/gered/views.reagent/tree/master/views.reagent
### Client/Server Plugin Documentation ### Client/Server Plugin Documentation
* **[views.reagent.sente][6]** provides fairly low-level integration with Sente. * **[views.reagent.sente][5]** provides fairly low-level integration with Sente.
* **[views.reagent.browserchannel][7]** for using BrowserChannel for client/server communication.
[6]: https://github.com/gered/views.reagent/tree/master/views.reagent.sente [5]: https://github.com/gered/views.reagent/tree/master/views.reagent.sente
[7]: https://github.com/gered/views.reagent/tree/master/views.reagent.browserchannel
If you're intent on using something else, you'll need to write your own client/server plugin
library. Previously I provided a BrowserChannel plugin in addition to the Sente plugin library,
but BrowserChannel is now pretty ancient and unnecessary since modern browsers universally support
Websockets, so it was removed in favour of using Sente.
### Examples ### Examples
There are two example applications for you to look at to see a fully working web application with working views system configured and working. There are two example applications for you to look at to see a fully working web application with
working views system configured and working.
* Todo MVC. There are two versions of this that are both largely identical except that [one uses Sente][8] and the [other uses BrowserChannel][9]. * [Todo MVC][6]. This is a copy of the original Reagent "Todo MVC" example app, but re-worked to
* [Class Registry][10]. This is a somewhat more complex application with a busy UI showing a bunch of data at once, but it does serve to show how a UI can be built from multiple different views at once. This example app uses Sente. use a SQL database and the views system.
* [Class Registry][7]. This is a somewhat more complex application with a busy UI showing a bunch
of data at once, but it does serve to show how a UI can be built from multiple different views
at once.
[8]: https://github.com/gered/views.reagent/tree/master/examples/todomvc [6]: https://github.com/gered/views.reagent/tree/master/examples/todomvc
[9]: https://github.com/gered/views.reagent/tree/master/examples/todomvc-browserchannel [7]: https://github.com/gered/views.reagent/tree/master/examples/class-registry
[10]: https://github.com/gered/views.reagent/tree/master/examples/class-registry
### Notes ### Notes
@ -55,15 +64,12 @@ like to integrate client/server communications in their applications. I wanted t
(as much as possible) doing anything that would require any specific way of doing this (as much as possible) doing anything that would require any specific way of doing this
kind of integration. kind of integration.
As well, speaking for myself, I use my own custom helper library that wraps over Sente which
I like but did not want to force anyone else to use.
The client/server glue code provided by these libraries is incredibly light so if they The client/server glue code provided by these libraries is incredibly light so if they
do not meet your needs for whatever reason you should find it easy to create one yourself. do not meet your needs for whatever reason you should find it easy to create one yourself.
## License ## License
Copyright © 2016 Gered King Copyright © 2022 Gered King
Distributed under the the MIT License. See LICENSE for more details. Distributed under the the MIT License. See LICENSE for more details.

View file

@ -1,21 +1,21 @@
(defproject gered/views.reagent.sente "0.2-SNAPSHOT" (defproject net.gered/views.reagent.sente "0.2-SNAPSHOT"
:description "Sente client/server messaging adapter for views.reagent." :description "Sente client/server messaging adapter for views.reagent."
:url "https://github.com/gered/views.reagent" :url "https://github.com/gered/views.reagent"
:license {:name "MIT License" :license {:name "MIT License"
:url "http://opensource.org/licenses/MIT"} :url "http://opensource.org/licenses/MIT"}
:dependencies [[org.clojure/clojure "1.8.0"]] :dependencies []
:plugins [[lein-cljsbuild "1.1.3"]] :plugins [[lein-cljsbuild "1.1.8"]]
:profiles {:provided :profiles {:provided
{:dependencies {:dependencies
[[org.clojure/clojure "1.8.0"] [[org.clojure/clojure "1.10.3"]
[org.clojure/clojurescript "1.8.51"] [org.clojure/clojurescript "1.10.773"]
[reagent "0.6.0-alpha"] [reagent "1.1.0"]
[gered/views "1.5"] [net.gered/views "1.6-SNAPSHOT"]
[gered/views.reagent "0.1"] [net.gered/views.reagent "0.2-SNAPSHOT"]
[com.taoensso/sente "1.8.1"]]}} [com.taoensso/sente "1.16.2"]]}}
:cljsbuild {:builds :cljsbuild {:builds
{:main {:main

View file

@ -21,6 +21,15 @@
(send-fn sente-chsk-map data)) (send-fn sente-chsk-map data))
(reset! send-buffer [])) (reset! send-buffer []))
(defn chsk-open-event?
"returns true if the sente event is for a channel-socket state change to 'open' or 'connected'."
[{:keys [event] :as ev}]
; for :chsk/state events, sente sends the event data in the form [old-state new-state].
; we only care about the new state for the purposes of performing this check ...
(let [[ev-id ev-data] event]
(and (= :chsk/state ev-id)
(:open? (second ev-data)))))
(defn on-open! (defn on-open!
"should be called when a new Sente connection is established. ev is the event "should be called when a new Sente connection is established. ev is the event
map provided by Sente where id = :chsk/state, and :open? = true. make sure map provided by Sente where id = :chsk/state, and :open? = true. make sure
@ -44,14 +53,12 @@
application does not need to do any custom Sente event handling, then you can application does not need to do any custom Sente event handling, then you can
opt to use this event handler." opt to use this event handler."
[sente-chsk-map {:keys [event id client-id] :as ev}] [sente-chsk-map {:keys [event id client-id] :as ev}]
(let [[ev-id ev-data] event]
(cond (cond
(and (= :chsk/state ev-id) (chsk-open-event? event)
(:open? ev-data))
(on-open! sente-chsk-map ev) (on-open! sente-chsk-map ev)
(= :chsk/recv id) (= :chsk/recv id)
(on-receive! sente-chsk-map ev)))) (on-receive! sente-chsk-map ev)))
(defn init! (defn init!
"performs initial configuration necessary to hook Sente into views.reagent as the "performs initial configuration necessary to hook Sente into views.reagent as the

View file

@ -1,11 +1,10 @@
# views.reagent # views.reagent
This is the main library for the [views.reagent project][1] which This is the main library for the [views.reagent project][1] which provides the core functionality
provides the core functionality that most of your application code will that most of your application code will make use of.
make use of.
Familiarity with the [views][2] library is *absolutely crucial* to Familiarity with the [views][2] library is *absolutely crucial* to understanding and usage of
understanding and usage of views.reagent. views.reagent.
[1]: https://github.com/gered/views.reagent [1]: https://github.com/gered/views.reagent
[2]: https://github.com/gered/views [2]: https://github.com/gered/views
@ -18,22 +17,19 @@ understanding and usage of views.reagent.
## Usage ## Usage
Much of this documentation will be referring to the Much of this documentation will be referring to the [Todo MVC example project][3] which uses
[Todo MVC example project][3] which uses
[Sente client/server messaging][4] and [SQL views][5]. [Sente client/server messaging][4] and [SQL views][5].
[3]: https://github.com/gered/views.reagent/tree/master/examples/todomvc [3]: https://github.com/gered/views.reagent/tree/master/examples/todomvc
[4]: https://github.com/gered/views.reagent/tree/master/views.reagent.sente [4]: https://github.com/gered/views.reagent/tree/master/views.reagent.sente
[5]: https://github.com/gered/views.sql [5]: https://github.com/gered/views.sql
Usage of this library is incredibly simple once you have a working Usage of this library is incredibly simple once you have a working views system up and running.
views system up and running.
Initialization of the views system is typically either done directly Initialization of the views system is typically either done directly via `views.core/init!` with
via `views.core/init!` with some special configuration for whatever some special configuration for whatever client/server messaging plugin you're using, or you may be
client/server messaging plugin you're using, or you may be required to required to call a special "init" function provided by the plugin library to use instead of
call a special "init" function provided by the plugin library to use `views.core/init!`.
instead of `views.core/init!`.
The Todo MVC example uses the following (server-side) view system: The Todo MVC example uses the following (server-side) view system:
@ -49,31 +45,26 @@ The Todo MVC example uses the following (server-side) view system:
[(view :todos db #'todos-list)]) [(view :todos db #'todos-list)])
``` ```
A single view named `:todos` which simply returns a list of all Todos A single view named `:todos` which simply returns a list of all Todos in the database. The view
in the database. The view takes no parameters. takes no parameters.
Over on the ClojureScript side of things, once a connection has been Over on the ClojureScript side of things, once a connection has been established to the server by
established to the server by the client/server messaging library, you the client/server messaging library, you are ready to start using **view cursors** in your Reagent
are ready to start using **view cursors** in your Reagent components. components.
### View Cursors ### View Cursors
A **view cursor** is simply a Reagent cursor that represents the A **view cursor** is simply a Reagent cursor that represents the underlying view data received
underlying view data received from the views library when the view is from the views library when the view is subscribed to. We can create a subscription by simply
subscribed to. We can create a subscription by simply creating a view creating a view cursor for the desired view and giving it any appropriate parameters.
cursor for the desired view and giving it any appropriate parameters. views.reagent will automatically determine if it's the first usage of the view cursor and if a
views.reagent will automatically determine if it's the first usage of subscription request needs to be sent to the server. When a view refresh is performed on the
the view cursor and if a subscription request needs to be sent to the server for the view, views.reagent sends it to the client and the data is put into a location
server. When a view refresh is performed on the server for the view, where it's available to the views cursor. Since view cursors are Reagent cursors, updating the
views.reagent sends it to the client and the data is put into a data like this instantly causes components dereferencing the cursor to rerender themselves. When
location where it's available to the views cursor. Since view cursors components are unmounted views.reagent will automatically unsubscribe from views as appropriate.
are Reagent cursors, updating the data like this instantly causes As well, when parameters passed in to view cursors change, view re-subscriptions are automatically
components dereferencing the cursor to rerender themselves. When handled to make sure the view cursor is always up to date with the current client state.
components are unmounted views.reagent will automatically unsubscribe
from views as appropriate. As well, when parameters passed in to view
cursors change, view re-subscriptions are automatically handled to make
sure the view cursor is always up to date with the current client
state.
So, how do we create a view cursor? So, how do we create a view cursor?
@ -91,36 +82,29 @@ So, how do we create a view cursor?
@(view-cursor :todos))]) @(view-cursor :todos))])
``` ```
Given the previously set up view system on the server, this is all the Given the previously set up view system on the server, this is all the UI code necessary to
UI code necessary to subscribe to the `:todos` view and retrieve and subscribe to the `:todos` view and retrieve and render the Todos list on the client. Whenever the
render the Todos list on the client. Whenever the `:todos` view is `:todos` view is refreshed on the server, the client will receive the data automatically and the
refreshed on the server, the client will receive the data automatically component will rerender since it is dereferencing the views cursor. Finally, the client will
and the component will rerender since it is dereferencing the views automatically unsubscribe from the `:todos` view when the `my-todos-list` component is unmounted.
cursor. Finally, the client will automatically unsubscribe from the
`:todos` view when the `my-todos-list` component is unmounted.
At first glance, `my-todos-list` looks just like any other normal At first glance, `my-todos-list` looks just like any other normal Reagent component. However a
Reagent component. However a very important difference is the use of very important difference is the use of `defvc` instead of `defn`.
`defvc` instead of `defn`.
`defvc` creates a Reagent **view component** which hooks into some `defvc` creates a Reagent **view component** which hooks into some React component lifecycle
React component lifecycle events to automatically handle view events to automatically handle view subscriptions/unsubscriptions for us based on how we use
subscriptions/unsubscriptions for us based on how we use `view-cursor` `view-cursor` inside the component. You ***must*** use `defvc` for all Reagent components within
inside the component. You ***must*** use `defvc` for all Reagent which you want to use `view-cursor`.
components within which you want to use `view-cursor`.
`view-cursor` returns a Reagent cursor containing the actual view data `view-cursor` returns a Reagent cursor containing the actual view data (in this case, a simple
(in this case, a simple list of Todos). It's important to note that at list of Todos). It's important to note that at first the view data returned will be `nil` since
first the view data returned will be `nil` since obviously the client obviously the client must first wait for the subscription to be processed by the server and then
must first wait for the subscription to be processed by the server and for the server to send back the initial view data. Once this happens the component will
then for the server to send back the initial view data. Once this automatically rerender as you would expect (showing the list of todos).
happens the component will automatically rerender as you would expect
(showing the list of todos).
You can check if the view cursor is still waiting on the initial set of You can check if the view cursor is still waiting on the initial set of data through the use of
data through the use of the `loading?` function. This can be used to the `loading?` function. This can be used to render some kind of "loading" message or something
render some kind of "loading" message or something similar if you'd similar if you'd prefer not to render empty data when components first load.
prefer not to render empty data when components first load.
```clj ```clj
(defvc my-todos-list [] (defvc my-todos-list []
@ -135,20 +119,18 @@ prefer not to render empty data when components first load.
@todos)]))) @todos)])))
``` ```
Note that `loading?` should be passed the actual Reagent cursor that Note that `loading?` should be passed the actual Reagent cursor that `view-cursor` returns, not
`view-cursor` returns, not the dereferenced result. the dereferenced result.
Also remember that `loading?` only checks if the view cursor is waiting Also remember that `loading?` only checks if the view cursor is waiting on the **initial** view
on the **initial** view data. Once that first set of data is received, data. Once that first set of data is received, `loading?` will always return false. There is no
`loading?` will always return false. There is no current method in current method in views.reagent for determining if a view refresh is pending, although this is
views.reagent for determining if a view refresh is pending, although typically somewhat of a less drastic UI change to the user so in practice it may be less of a
this is typically somewhat of a less drastic UI change to the user so concern.
in practice it may be less of a concern.
#### View Parameters #### View Parameters
Some of your views may take parameters. This is easily supported by Some of your views may take parameters. This is easily supported by views.reagent.
views.reagent.
As an example, if our `:todos` view was updated to include a filter: As an example, if our `:todos` view was updated to include a filter:
@ -182,26 +164,23 @@ Letting us do any of these on the client:
#### View Cursors Are Intended To Be Read-only #### View Cursors Are Intended To Be Read-only
Even though a Reagent cursor allows you to update them as well as read Even though a Reagent cursor allows you to update them as well as read from them, updating a view
from them, updating a view cursor doesn't do anything. Nothing stops cursor doesn't do anything. Nothing stops you from doing this, but updating a view cursor does not
you from doing this, but updating a view cursor does not propagate propagate changes to the server or anything like that. In addition, you will lose any changes you
changes to the server or anything like that. In addition, you will lose make every time a view refresh is received as the data gets blindly replaced.
any changes you make every time a view refresh is received as the data
gets blindly replaced.
It is recommended that you do not write code that updates a view cursor. It is recommended that you do not write code that updates a view cursor.
## Advanced Topics ## Advanced Topics
Most people just looking to use views.reagent in their applications Most people just looking to use views.reagent in their applications probably won't need to read
probably won't need to read anything in this section. anything in this section.
### Manually Managing View Subscriptions ### Manually Managing View Subscriptions
For those applications with very specific/complex requirements, you can For those applications with very specific/complex requirements, you can manually subscribe and
manually subscribe and unsubscribe to views from your ClojureScript unsubscribe to views from your ClojureScript code using views.reagent as well as make use of view
code using views.reagent as well as make use of view cursors outside of cursors outside of Reagent components. I do not recommend this though.
Reagent components. I do not recommend this though.
```clj ```clj
(use 'views.reagent.client.core) (use 'views.reagent.client.core)
@ -217,50 +196,41 @@ Reagent components. I do not recommend this though.
(unsubscribe! [{:view-id :todos :parameters []}]) (unsubscribe! [{:view-id :todos :parameters []}])
``` ```
When using these low-level functions, you need to specify view When using these low-level functions, you need to specify view signature maps (a.k.a. "view sigs")
signature maps (a.k.a. "view sigs") to refer to the views you want to to refer to the views you want to use. Also note that unlike the server-side view signatures that
use. Also note that unlike the server-side view signatures that you may you may be familiar with from the views library, these client-side view signatures never have a
be familiar with from the views library, these client-side view `:namespace` in them. Even if you include one, it is disregarded by the server.
signatures never have a `:namespace` in them. Even if you include one,
it is disregarded by the server.
Also note that `subscribe!` and `unsubscribe!` both take a list of view Also note that `subscribe!` and `unsubscribe!` both take a list of view signatures, so you can
signatures, so you can subscribe and unsubscribe from multiple views at subscribe and unsubscribe from multiple views at once.
once.
I do not recommend mixing use of these low-level functions and using I do not recommend mixing use of these low-level functions and using `defvc` components. You
`defvc` components. You should probably pick one or the other and stick should probably pick one or the other and stick to it unless you really know what you're doing.
to it unless you really know what you're doing.
### Integration Points for Writing a Client/Server Messaging Plugin ### Integration Points for Writing a Client/Server Messaging Plugin
If you would like to write your own client/server messaging plugin If you would like to write your own client/server messaging plugin library to fit your own needs
library to fit your own needs you can easily do so. There are a couple you can easily do so. There are a couple integration points within the main views.reagent library,
integration points within the main views.reagent library, as well as as well as some special configuration you will need to provide to the views system that you need
some special configuration you will need to provide to the views system to be aware of.
that you need to be aware of.
#### View Subscriber Key #### View Subscriber Key
In the views library, a bunch of functions take a "subscriber key." In the views library, a bunch of functions take a "subscriber key." This is an arbitrary value
This is an arbitrary value that uniquely identifies a subscriber. There that uniquely identifies a subscriber. There can of course be multiple views for each subscriber
can of course be multiple views for each subscriber key. Said another key. Said another way: someone (uniquely identified by the subscriber key) can be subscribed to
way: someone (uniquely identified by the subscriber key) can be multiple different views at the same time.
subscribed to multiple different views at the same time.
You will typically want to use the underlying client/server library's You will typically want to use the underlying client/server library's "client/user connection ID"
"client/user connection ID" as the subscriber key. For Sente this is as the subscriber key. For Sente this is almost certainly going to be the "user id" or the
the "user id" or the "client id" (depending on your application), and "client id" (depending on your application).
for clj-browserchannel this is the BrowserChannel "session id."
#### View System Configuration #### View System Configuration
You need to provide a `:send-fn` function that can be provided in the You need to provide a `:send-fn` function that can be provided in the options given to
options given to `views.core/init!`. This function is used by the views `views.core/init!`. This function is used by the views library to send view refreshes to
library to send view refreshes to subscribers. For views.reagent, your subscribers. For views.reagent, your send-fn function should send a vector with 3 things in it:
send-fn function should send a vector with 3 things in it: the keyword the keyword `:views/refresh` followed by the `view-sig` and then `view-data`. For example:
`:views/refresh` followed by the `view-sig` and then `view-data`. For
example:
```clj ```clj
(defn send-fn (defn send-fn
@ -270,50 +240,43 @@ example:
#### Server-side Handling #### Server-side Handling
`views.reagent.server.core` has two main event handling functions that `views.reagent.server.core` has two main event handling functions that provide proper handling
provide proper handling for client connection events: for client connection events:
* `on-close!` should be called when a client's connection is closed for * `on-close!` should be called when a client's connection is closed for whatever reason.
whatever reason. views.reagent will remove all of the client's views.reagent will remove all of the client's subscriptions.
subscriptions. * `on-receive!` should be called and passed in the raw data from every message received from the
* `on-receive!` should be called and passed in the raw data from every client. It will return `true` if views.reagent recognized and handled the message as a
message received from the client. It will return `true` if subscription or unsubscription request. See `views.reagent.utils/relevant-event?` for how it
views.reagent recognized and handled the message as a subscription or recognizes relevant messages.
unsubscription request. See `views.reagent.utils/relevant-event?` for
how it recognizes relevant messages.
For both of these functions, `client-id` should be the subscriber key For both of these functions, `client-id` should be the subscriber key from the views library, and
from the views library, and `context` can be anything you wish. `context` can be anything you wish. Typically you will want to use something like a Ring request
Typically you will want to use something like a Ring request map and/or map and/or user profile data as the context. This context argument is what gets passed to
user profile data as the context. This context argument is what gets `views.core/subscribe!` and `views.core/unsubscribe!`.
passed to `views.core/subscribe!` and `views.core/unsubscribe!`.
#### Client-side Handling #### Client-side Handling
`views.reagent.client.core` also has two main event handling functions `views.reagent.client.core` also has two main event handling functions that provide proper
that provide proper handling for server connection events: handling for server connection events:
* `on-open!` should be called when a connection to the server is * `on-open!` should be called when a connection to the server is established (and re-established,
established (and re-established, if applicable). views.reagent will if applicable). views.reagent will re-send subscription requests for any subscriptions that
re-send subscription requests for any subscriptions that should exist should exist (e.g. if the connection was lost and the application reconnected, resubscribe to
(e.g. if the connection was lost and the application reconnected, the views that all current mounted components need).
resubscribe to the views that all current mounted components need). * `on-receive!` should be called and passed in the raw data from every message received from the
* `on-receive!` should be called and passed in the raw data from every server. It will return `true` if views.reagent recognized and handled the message as a view
message received from the server. It will return `true` if refresh event. See `views.reagent.utils/relevant-event?` for how it recognizes relevant messages.
views.reagent recognized and handled the message as a view refresh
event. See `views.reagent.utils/relevant-event?` for how it recognizes
relevant messages.
You also need to provide a function to send messages to the server. You also need to provide a function to send messages to the server. You can set this function by
You can set this function by directly using `reset!` on the atom directly using `reset!` on the atom `views.reagent.client/send-fn`. The function should take a
`views.reagent.client/send-fn`. The function should take a single single argument which is the data to be sent.
argument which is the data to be sent.
You should take care to hook up all of these integration points before You should take care to hook up all of these integration points before the first Reagent component
the first Reagent component is rendered at page load. is rendered at page load.
## License ## License
Copyright © 2016 Gered King Copyright © 2022 Gered King
Distributed under the the MIT License. See LICENSE for more details. Distributed under the the MIT License. See LICENSE for more details.

View file

@ -1,19 +1,19 @@
(defproject gered/views.reagent "0.2-SNAPSHOT" (defproject net.gered/views.reagent "0.2-SNAPSHOT"
:description "Reagent plugin for the views library, providing real-time component updates to server-side changes to data." :description "Reagent plugin for the views library, providing real-time component updates to server-side changes to data."
:url "https://github.com/gered/views.reagent" :url "https://github.com/gered/views.reagent"
:license {:name "MIT License" :license {:name "MIT License"
:url "http://opensource.org/licenses/MIT"} :url "http://opensource.org/licenses/MIT"}
:dependencies [[org.clojure/tools.logging "0.3.1"]] :dependencies [[org.clojure/tools.logging "1.2.4"]]
:plugins [[lein-cljsbuild "1.1.3"]] :plugins [[lein-cljsbuild "1.1.8"]]
:profiles {:provided :profiles {:provided
{:dependencies {:dependencies
[[org.clojure/clojure "1.8.0"] [[org.clojure/clojure "1.10.3"]
[org.clojure/clojurescript "1.8.51"] [org.clojure/clojurescript "1.10.773"]
[reagent "0.6.0-alpha"] [reagent "1.1.0"]
[gered/views "1.5"]]}} [net.gered/views "1.6-SNAPSHOT"]]}}
:cljsbuild {:builds :cljsbuild {:builds
{:main {:main

View file

@ -28,8 +28,8 @@
[args & body] decl] [args & body] decl]
`(defn ~component-name ~attr-map [] `(defn ~component-name ~attr-map []
(reagent.core/create-class (reagent.core/create-class
{:component-will-mount {:constructor
(fn [this#] (fn [this# props#]
(views.reagent.client.component/prepare-for-render! this#)) (views.reagent.client.component/prepare-for-render! this#))
:component-did-mount :component-did-mount
@ -43,14 +43,11 @@
(fn [this#] (fn [this#]
(views.reagent.client.component/unsubscribe-all! this#)) (views.reagent.client.component/unsubscribe-all! this#))
:component-will-receive-props
(fn [this# new-argv#]
(views.reagent.client.component/prepare-for-render! this#))
:component-did-update :component-did-update
(fn [this# old-argv#] (fn [this# old-argv#]
(views.reagent.client.component/update-subscriptions! this#)) (views.reagent.client.component/update-subscriptions! this#))
:component-function :reagent-render
(fn ~args (fn ~args
(views.reagent.client.component/prepare-for-render! (reagent.core/current-component))
~@body)})))) ~@body)}))))