Sfoglia il codice sorgente

move equality props to Component

Adam Shaw 7 anni fa
parent
commit
4f7d5afe82
2 ha cambiato i file con 49 aggiunte e 19 eliminazioni
  1. 47 6
      src/component/Component.ts
  2. 2 13
      src/util/object.ts

+ 47 - 6
src/component/Component.ts

@@ -2,7 +2,7 @@ import Calendar from '../Calendar'
 import View from '../View'
 import Theme from '../theme/Theme'
 import { DateEnv } from '../datelib/env'
-import { isPropsEqual, assignTo, EqualityFuncHash } from '../util/object'
+import { assignTo } from '../util/object'
 
 let guid = 0
 
@@ -14,12 +14,14 @@ export interface ComponentContext {
   view?: View
 }
 
+export type EqualityFuncHash = { [propName: string]: (obj0, obj1) => boolean }
+
 export default class Component<PropsType> {
 
-  equalityFuncs: EqualityFuncHash
+  equalityFuncs: EqualityFuncHash // can't initialize here. done below...
 
   uid: string
-  props: PropsType | null // non-null signals that a render happened
+  props: PropsType | null
 
   // context vars
   context: ComponentContext
@@ -52,9 +54,12 @@ export default class Component<PropsType> {
   }
 
   receiveProps(props: PropsType) {
-    if (!this.props || !isPropsEqual(this.props, props, this.equalityFuncs)) {
-      this.props = props
-      this.render(props)
+    let { anyChanges, comboProps } = recycleProps(this.props || {}, props, this.equalityFuncs)
+
+    this.props = comboProps
+
+    if (anyChanges) {
+      this.render(comboProps)
     }
   }
 
@@ -66,3 +71,39 @@ export default class Component<PropsType> {
   }
 
 }
+
+Component.prototype.equalityFuncs = {}
+
+
+/*
+Reuses old values when equal. If anything is unequal, returns newProps as-is.
+Great for PureComponent, but won't be feasible with React, so just eliminate and use React's DOM diffing.
+*/
+function recycleProps(oldProps, newProps, equalityFuncs: EqualityFuncHash) {
+  let comboProps = {} as any // some old, some new
+  let anyChanges = false
+
+  for (let key in newProps) {
+    if (
+      key in oldProps && (
+        oldProps[key] === newProps[key] ||
+        (equalityFuncs[key] && equalityFuncs[key](oldProps[key], newProps[key]))
+      )
+    ) {
+      // equal to old? use old prop
+      comboProps[key] = oldProps[key]
+    } else {
+      comboProps[key] = newProps[key]
+      anyChanges = true
+    }
+  }
+
+  for (let key in oldProps) {
+    if (!(key in newProps)) {
+      anyChanges = true
+      break
+    }
+  }
+
+  return { anyChanges, comboProps }
+}

+ 2 - 13
src/util/object.ts

@@ -120,21 +120,10 @@ export function arrayToHash(a): { [key: string]: true } {
 }
 
 
-export type EqualityFuncHash = { [propName: string]: (obj0, obj1) => boolean }
+export function isPropsEqual(obj0, obj1): boolean {
 
-export function isPropsEqual(obj0, obj1, equalities: EqualityFuncHash = {}): boolean {
   for (let key in obj0) {
-    let val0 = obj0[key]
-    let val1 = obj1[key]
-
-    if (
-      val0 !== val1 &&
-      !(
-        equalities[key] &&
-        val1 !== undefined && // we already know val0 exists
-        equalities[key](val0, val1)
-      )
-    ) {
+    if (obj0[key] !== obj1[key]) {
       return false
     }
   }