I implemented a slider component in Reagent + D3 using reagent/create-class:
(ns slider
(:require [reagent.core :as reagent]
[reagent.impl.util :as util]))
(defn slider [{:keys [name width height value on-change]}]
(let [w (or width 150)
h (or height 20)]
(reagent/create-class {
:component-did-mount
(fn [this]
(let [pos->value #(-> js/d3 (.mouse (.getDOMNode this)) first (/ w) (min 1) (max 0))
on-drag #(on-change (pos->value))
drag (-> js/d3 .-behavior .drag
(.on "drag" on-drag))]
(-> js/d3
(.select (.getDOMNode this))
(.call drag))))
:render (fn [this]
(let [value (-> this util/get-props :value)]
[:svg {:width w :height h}
[:g {:className "slider"}
[:rect {:className "slider__rect" :x 1 :y 1 :width (- w 3) :height (- h 3) }]
[:rect {:className "slider__fill__rect"
:x 2 :y 2
:width (- (* w value) 4) :height (- h 4) }]
[:text {:className "slider__text" :x (/ w 2) :y (/ h 2)} name]]]))})))
Here the properties of the component are specified in the outer "slider" function. The values of these function params, however, are not getting updated when accessed from the inner render function on subsequent calls, of course. So the value of the parameter "value" always stays the same as when the component was first created, even if the actual property has changed. This is ugly and was a source of confusion for me.
I could resort to calling reagent.impl.util/get-props to get the most current property values in "render", and it works. However, get-props seems to be an internal function, so it is probably not intended to be called directly.
When using the alternative way of constructing components with "with-meta", the properties are passed as parameters directly to the render function. Hence, render always sees the most current values:
(def slider
(with-meta
(fn [{:keys [name width height value on-change]}] ...)
{:component-did-mount
(fn [this] ...)}))
This way there is at least less confusion, because there are no variables with obsolete property values here. But component-did-mount does not get the properties directly and has to use get-props again.
Personally, I would prefer using create-class for components with extra life-cycle functions, but this confusion with the variables getting obsolete makes it much less attractive than it could be.
Am I missing something obvious? What is the proper way of defining component properties which allows all the life-cycle functions to see them?
Thanks in advance!
Ilya