Name: re-fill
Owner: Metosin
Description: A collection of Re-frame components that most applications need.
Created: 2017-08-15 06:26:01.0
Updated: 2018-05-24 11:42:01.0
Pushed: 2017-10-12 12:09:22.0
Homepage: null
Size: 25
Language: Clojure
GitHub Committers
User | Most Recent Commit | # Commits |
---|
Other Committers
User | Most Recent Commit | # Commits |
---|
A collection of Re-frame components that most applications need. Currently, Re-fill offers event handlers, subscriptions, effects and co-effects for:
Re-fill contains multiple utilities, which all have their own namespaces. It's possible to use only one of the utilities, or any combination of them. As in Re-frame, event handlers, subscriptions etc. will be registered globally after requiring the specific namespace for the wanted utility.
Routing utility provides means to listen for URL changes and dispatch events based on them, making it possible to write bookmarkable single-page apps with ease.
Currently, Re-fill only supports routes defined using Bidi syntax. For listening the URL in your address bar, Re-fill uses Pushy.
To use Re-fill for routing, first require the correct namespace(s):
example.core
require [reagent.core :as r]
[re-frame.core :as rf]
[re-fill.routing :as routing]))
Then, define your routes using Bidi syntax (no need to add dependency for it though). For example:
routes ["/" {"" :routes/home
["page/" :id] :routes/page}])
It's recommended to use namespaced keywords, as those keywords will be dispatched by Re-frame.
You also need to create mappings between routes and views:
views {:routes/home home-view
:routes/page page-view
;; Value of :else will be used if there's no mapping for route
:else loading-view})
In order to render the correct view, add routed-view
in your root view
/ template, and give the mappings from previous step to it as argument.
Here's an example:
n main-view
iews]
div.main
:h1 "This is shown in all views"]
; views refers to the mappings created in the previous step
routing/routed-view views]])
Lastly, in order to initialize the routing, dispatch
:re-fill/init-routing
during the startup of the application:
n init!
routes refer to your Bidi-routes
f/dispatch [:re-fill/init-routing routes])
views refer to your route - view mappings
/render [main-view views]
(js/document.getElementById "app")))
t!)
After doing this, the URL in the address bar will be listened by Re-fill
and the corresponding view will be rendered by template. You can either use
links normally with hrefs (no preventDefault or manual history manipulation
is needed), or dispatch `:re-fill/navigate
` event to navigate
programmatically. Here's an example of both:
v
Normal navigation with link
.controls__a {:href "/page/1"} "Page 1 (by link)"]
Navigation by dispatching an event
utton.controls__button
on-click (fn [_]
(rf/dispatch [:re-fill/navigate
;; The argument to re-fill/navigate is the actual
;; route with path-params.
;; See Bidi documentation for more information
[:routes/page :id 2]]))}
age 2 (by dispatch)"]]
The event `:re-fill/navigate
` is great for initiating navigation from views.
There's also an effect handler for :re-fill/navigate, which makes it
possible to navigate from event handlers without dispatching more events.
This is useful for cases where the view dispatches an event, and the event
handler may conditionally initiate navigation to some other view in addition
to other side effects (through effects of course).
If you need to refer to your current route from your views, you can use
(defn page-view [] (let [routing @(rf/subscribe [:re-fill/routing])]
[:h1 (pr-str routing)]))
r navigation happens, Re-fill dispatches an event using the route key as
dentifier for it. It's recommended to register an event handler for each
he routes, otherwise you get a warning to console about a missing event
ler. This dispatched event is great for setting up the state for the view
's gonna be rendered. Here's a simple example:
(rf/reg-event-fx :routes/home ;; The first argument is the co-effects (normal Re-frame stuff) ;; The second argument is the event itself. The route match ;; from bidi can be destructured from it (fn [ [ bidi-match]] ;; In real apps, this function would return effects map for ;; fetching data, setting state or something else. (js/console.log “Navigated to " bidi-match)))
l example](https://github.com/metosin/re-fill/tree/master/example-src/example/core.cljs)
more information.
Notifications
fications utility provides a generic notification interface for
ting and deleting notifications, and a subscription for using them
our views. Notifications are often used to show information or warning
ogs to end-users.
rder to use notifications, the correct namespaces must be required:
(ns example.core (:require [re-frame.core :as rf]
[re-fill.notifications :as notifications]))
r that, notifications can be created with ```:re-fill/notify``` event.
example:
[:button.controls_button {:on-click (fn [] (rf/dispatch [:re-fill/notify
;; The first argument is the data
;; you want to use as notification.
;; It's your responsibility to add types
;; your notifications if you need them.
{:type :success
:content "Success!"}
;; The second (optional) argument is used
;; by re-fill to configure the notification.
;; Currently, the only supported key is
;; :hide-after, which can be used to delete
;; the notification after a given time (in
;; ms) has passed.
{:hide-after 3000}]))}
“Notify success!“]
``:hide-after``` is used, the notification will be removed automatically
r the timeout has passed. In order to delete the notification manually,
```:re-fill/delete-notification``` event can be used.
ew must be created for rendering notifications. Re-fill provides a
cription ```:re-fill/notifications``` for getting the notifications
iew functions.
's a simple view to demonstrate the usage of
subscription:
n notifications-view
Subscription to notifications
et [notifications @(rf/subscribe [:re-fill/notifications])]
[:div.notifications
(for [{:keys [id type content]} notifications]
[:div.notification
{:key id
:class (case type
:success "notification--success"
:warning "notification--warning")}
[:span.notification__span content]
[:button.notification__button
;; Deleting a notification requires the id of notification
;; Unique id is generated automatically by Re-fill
{:on-click #(rf/dispatch [:re-fill/delete-notification id])}
"x"]])]))
See full example for more information.
Debounce utility can be used for:
For those who are new to debounce there's a good explanation of debounce at css-tricks.com
To use debounce utility, the correct namespaces must be required:
example.core
require [re-frame.core :as rf]
[re-fill.debounce :as debounce]))
To schedule an event to the future, the event `:re-fill/debounce
can be
used. Here's an example of how to schedule the ``
:re-fill/notify``` with
a one second timeout.
tton.controls__button
n-click (fn [_] (rf/dispatch [:re-fill/debounce
;; The :id is used to identify the scheduled
;; event. If :id is not supplied, the id of
;; the event will be used.
{:id :test-notify
;; The actual event that will be dispatched
;; or debounced.
:event [:re-fill/notify
{:type :success
:content "From debounce!"}
{:hide-after 3000}]
;; Timeout in ms for scheduling the dispatch
;; to the future.
:timeout 1000}]))}
"Notify with debounce"]
Debounce is more than just `:dispatch-later
` built into Re-frame: this
scheduled event can be moved further into the future by dispatching
means that in the example above the ```:re-fill/notify``` event won't be
atched ever if the user keeps clicking the button repeatedly with the less
one second intervals.
unce is great for dispatching events after the user has stopped doing
thing that results in multiple browser events, such as starting a search
r the user has stopped typing.
e's also a subscription ```:re-fill/debounce``` for getting all the
duled events which have not yet been dispatched. Debounce utility also
ws canceling the dispatch of the event while the timeout is still active
sing the ```:re-fill/stop-debounce``` event.
's an example of a cancel button which is only clickable if the event has
duled
(defn cancel-button [] (let [debounce @(rf/subscribe [:re-fill/debounce])]
[:button.controls__button
{:on-click (fn [_] (rf/dispatch [:re-fill/stop-debounce :test-notify]))
:disabled (not (:test-notify debounce))}
"Stop debounce"]))
l example](https://github.com/metosin/re-fill/tree/master/example-src/example/core.cljs)
more information.
UUIDs
ill provides a co-effect ```:re-fill/uuids``` for injecting UUIDs to
t handlers. In fact, the ```:re-fill/notify``` event handler uses
nternally to generate unique ids for each notification.
to be created. Here's an example of how to use it:
e-fill.uuid must be required
reg-event-fx
ur/event
f/inject-cofx :re-fill/uuids 2)]
:uuids can be destructured from co-effects
[{:keys [db uuids]} _]
; uuids is a vector of 2 UUIDs
)
Here's how re-fill.notifications utilizes this.
All the files for actual library are located under src directory. There's an example app for development and testing under example-src and example-resources directories.
To get an interactive development environment run:
lein figwheel
and your browser will open automatically at localhost:3449. From there, you get the normal Figwheel development flow.
deploy clojars
Copyright © 2017 Metosin
Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.