From 8be155f56b31b3661e093fc04608d28a4fdff531 Mon Sep 17 00:00:00 2001 From: Thomas Scheiblauer Date: Fri, 27 May 2016 18:00:57 +0200 Subject: [PATCH 1/3] implement a generic solution for setting a react key on a component from outside the component. This has the advantage that neither every component that may be part of a sequence has to implement a :keyfn function nor does the component have to know that fact and how to generate a key which will not be needed by the component for any other purpose. To keep the current API and since the key actually IS metadata this is accomplished by setting metadata on the components value at call time using the with-key function, e.g. (MyComponent (with-key value key) ...), which will override :keyfn. The only restriction for this to work is that the component's value has to be a datatype which may carry metadata (implements the IWithMeta interface) like vectors, hashmaps, etc... --- src/quiescent/core.cljs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/quiescent/core.cljs b/src/quiescent/core.cljs index 7061846..a8d181b 100644 --- a/src/quiescent/core.cljs +++ b/src/quiescent/core.cljs @@ -56,6 +56,9 @@ [method (impl-ctor impl)])))) opts-map))) +(defn with-key [value react-key] + (vary-meta value assoc ::key react-key)) + (defn component "Return a factory function that will create a ReactElement, using the provided function as the 'render' method for a ReactJS component, which is created and instantiated behind-the-scenes. @@ -72,6 +75,13 @@ :keyfn - a single-argument function which is invoked at component construction time. It is passed the component's value, and returns the ReactJS key used to uniquely identify this component among its children. + The key may also be set as metadata of the components value at call time using the with-key + function, e.g. (MyComponent (with-key value key) ...), which will override :keyfn. + This has the advantage that neither every component that may be part of a sequence has to + implement a :keyfn function nor does the component have to know that fact and how to generate + a key which will not be needed by the component for any other purpose. The only restriction + for this to work is that the component's value has to be a datatype which may carry metadata + (implements the IWithMeta interface) like vectors, hashmaps, etc... :name - the name of the element, used for debugging purposes. @@ -138,8 +148,9 @@ (let [props (js-obj)] (set! (.-value props) value) (set! (.-constants props) constant-args) - (when-let [keyfn (:keyfn opts)] - (set! (.-key props) (keyfn value))) + (when-let [react-key (or (::key (meta value)) + (when-let [keyfn (:keyfn opts)] (keyfn value)))] + (set! (.-key props) react-key)) (.createElement js/React react-component props)))))) (defn unmount From fcc20d6967e828365b5c610f30d113ff5dac8963 Mon Sep 17 00:00:00 2001 From: Thomas Scheiblauer Date: Fri, 12 Aug 2016 21:58:53 +0200 Subject: [PATCH 2/3] improve 'with-key' technique by using a deftype instead of metadata thus allowing to use a scalar value for component state --- src/quiescent/core.cljs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/quiescent/core.cljs b/src/quiescent/core.cljs index a8d181b..92e320c 100644 --- a/src/quiescent/core.cljs +++ b/src/quiescent/core.cljs @@ -56,8 +56,10 @@ [method (impl-ctor impl)])))) opts-map))) +(deftype ValueWithKey [value react-key]) + (defn with-key [value react-key] - (vary-meta value assoc ::key react-key)) + (ValueWithKey. value react-key)) (defn component "Return a factory function that will create a ReactElement, using the provided function as the @@ -75,13 +77,11 @@ :keyfn - a single-argument function which is invoked at component construction time. It is passed the component's value, and returns the ReactJS key used to uniquely identify this component among its children. - The key may also be set as metadata of the components value at call time using the with-key + The key may also be set by applying a key to the value at call time using the with-key function, e.g. (MyComponent (with-key value key) ...), which will override :keyfn. This has the advantage that neither every component that may be part of a sequence has to implement a :keyfn function nor does the component have to know that fact and how to generate - a key which will not be needed by the component for any other purpose. The only restriction - for this to work is that the component's value has to be a datatype which may carry metadata - (implements the IWithMeta interface) like vectors, hashmaps, etc... + a key which will not be needed by the component for any other purpose. :name - the name of the element, used for debugging purposes. @@ -145,12 +145,13 @@ (build-lifecycle-impls opts)) react-component (.createClass js/React (clj->js impl))] (fn [value & constant-args] - (let [props (js-obj)] - (set! (.-value props) value) + (let [props (js-obj) + [real-value react-key] (if (instance? ValueWithKey value) + [(.-value value) (.-key value)] + [value (when-let [keyfn (:keyfn opts)] (keyfn value))])] + (set! (.-value props) real-value) (set! (.-constants props) constant-args) - (when-let [react-key (or (::key (meta value)) - (when-let [keyfn (:keyfn opts)] (keyfn value)))] - (set! (.-key props) react-key)) + (when react-key (set! (.-key props) react-key)) (.createElement js/React react-component props)))))) (defn unmount From 8f82c43f6b8a87df4b2aa5eb59ac4a044630afed Mon Sep 17 00:00:00 2001 From: Thomas Scheiblauer Date: Fri, 12 Aug 2016 22:07:39 +0200 Subject: [PATCH 3/3] fix property name --- src/quiescent/core.cljs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/quiescent/core.cljs b/src/quiescent/core.cljs index 92e320c..7ca2082 100644 --- a/src/quiescent/core.cljs +++ b/src/quiescent/core.cljs @@ -147,7 +147,7 @@ (fn [value & constant-args] (let [props (js-obj) [real-value react-key] (if (instance? ValueWithKey value) - [(.-value value) (.-key value)] + [(.-value value) (.-react-key value)] [value (when-let [keyfn (:keyfn opts)] (keyfn value))])] (set! (.-value props) real-value) (set! (.-constants props) constant-args)