Compare component arguments with = in shouldComponentUpdate

This makes most comparisons faster, and should result in fewer
re-renderings. And it should be a lot easier to explain and
reason about than the old heuristics.

It also makes it much easier to make custom objects, e.g. different
cursor implementations, avoid unnecessary re-renderings.

The main downside is that it is no longer possible to pass infinite
sequences to components.
This commit is contained in:
Dan Holmsand 2014-11-06 19:45:49 +01:00
parent d74ae49c70
commit cf84b88e60
2 changed files with 44 additions and 39 deletions

View File

@ -3,6 +3,8 @@
## Upcoming
- Arguments to components are now compared using simple `=`, instead of the old, rather complicated heuristics. **NOTE**: This means all arguments to a component function must be comparable with `=` (which means that they cannot be for example infinite `seq`s).
- React updated to 0.12.0. Reagent now creates all React components using `React.createElement`.
- `render-component` is now render, and `render-component-to-string` is `render-to-string`, in order to match React 0.12.0 (but the old names still work).

View File

@ -162,43 +162,46 @@
;;; Helpers for shouldComponentUpdate
(def -not-found (js-obj))
(defn identical-ish? [x y]
(or (keyword-identical? x y)
(and (or (symbol? x)
(identical? (type x) partial-ifn))
(= x y))))
(defn shallow-equal-maps [x y]
;; Compare two maps, using identical-ish? on all values
(or (identical? x y)
(and (map? x)
(map? y)
(== (count x) (count y))
(reduce-kv (fn [res k v]
(let [yv (get y k -not-found)]
(if (or (identical? v yv)
(identical-ish? v yv)
;; Handle :style maps specially
(and (keyword-identical? k :style)
(shallow-equal-maps v yv)))
res
(reduced false))))
true x))))
(defn equal-args [v1 v2]
;; Compare two vectors using identical-ish?
(assert (vector? v1))
(assert (vector? v2))
(or (identical? v1 v2)
(and (== (count v1) (count v2))
(reduce-kv (fn [res k v]
(let [v' (nth v2 k)]
(if (or (identical? v v')
(identical-ish? v v')
(and (map? v)
(shallow-equal-maps v v')))
res
(reduced false))))
true v1))))
(= v1 v2))
;; (def -not-found (js-obj))
;; (defn identical-ish? [x y]
;; (or (keyword-identical? x y)
;; (and (or (symbol? x)
;; (identical? (type x) partial-ifn))
;; (= x y))))
;; (defn shallow-equal-maps [x y]
;; ;; Compare two maps, using identical-ish? on all values
;; (or (identical? x y)
;; (and (map? x)
;; (map? y)
;; (== (count x) (count y))
;; (reduce-kv (fn [res k v]
;; (let [yv (get y k -not-found)]
;; (if (or (identical? v yv)
;; (identical-ish? v yv)
;; ;; Handle :style maps specially
;; (and (keyword-identical? k :style)
;; (shallow-equal-maps v yv)))
;; res
;; (reduced false))))
;; true x))))
;; (defn equal-args [v1 v2]
;; ;; Compare two vectors using identical-ish?
;; (assert (vector? v1))
;; (assert (vector? v2))
;; (or (identical? v1 v2)
;; (and (== (count v1) (count v2))
;; (reduce-kv (fn [res k v]
;; (let [v' (nth v2 k)]
;; (if (or (identical? v v')
;; (identical-ish? v v')
;; (and (map? v)
;; (shallow-equal-maps v v')))
;; res
;; (reduced false))))
;; true v1))))