Component.ts 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. import Calendar from '../Calendar'
  2. import View from '../View'
  3. import Theme from '../theme/Theme'
  4. import { DateEnv } from '../datelib/env'
  5. let guid = 0
  6. export interface ComponentContext {
  7. options: any
  8. dateEnv: DateEnv
  9. theme: Theme
  10. calendar: Calendar
  11. view: View
  12. }
  13. export type EqualityFuncHash = { [propName: string]: (obj0, obj1) => boolean }
  14. export default class Component<PropsType> {
  15. equalityFuncs: EqualityFuncHash // can't initialize here. done below...
  16. uid: string
  17. props: PropsType | null
  18. // context vars
  19. context: ComponentContext
  20. dateEnv: DateEnv
  21. theme: Theme
  22. view: View
  23. calendar: Calendar
  24. isRtl: boolean
  25. constructor(context: ComponentContext, isView?: boolean) {
  26. // HACK to populate view at top of component instantiation call chain
  27. if (isView) {
  28. context.view = this as any
  29. }
  30. this.uid = String(guid++)
  31. this.context = context
  32. this.dateEnv = context.dateEnv
  33. this.theme = context.theme
  34. this.view = context.view
  35. this.calendar = context.calendar
  36. this.isRtl = this.opt('dir') === 'rtl'
  37. }
  38. static addEqualityFuncs(newFuncs: EqualityFuncHash) {
  39. this.prototype.equalityFuncs = {
  40. ...this.prototype.equalityFuncs,
  41. ...newFuncs
  42. }
  43. }
  44. opt(name) {
  45. return this.context.options[name]
  46. }
  47. receiveProps(props: PropsType) {
  48. let { anyChanges, comboProps } = recycleProps(this.props || {}, props, this.equalityFuncs)
  49. this.props = comboProps
  50. if (anyChanges) {
  51. this.render(comboProps)
  52. }
  53. }
  54. protected render(props: PropsType) {
  55. }
  56. // after destroy is called, this component won't ever be used again
  57. destroy() {
  58. }
  59. }
  60. Component.prototype.equalityFuncs = {}
  61. /*
  62. Reuses old values when equal. If anything is unequal, returns newProps as-is.
  63. Great for PureComponent, but won't be feasible with React, so just eliminate and use React's DOM diffing.
  64. */
  65. function recycleProps(oldProps, newProps, equalityFuncs: EqualityFuncHash) {
  66. let comboProps = {} as any // some old, some new
  67. let anyChanges = false
  68. for (let key in newProps) {
  69. if (
  70. key in oldProps && (
  71. oldProps[key] === newProps[key] ||
  72. (equalityFuncs[key] && equalityFuncs[key](oldProps[key], newProps[key]))
  73. )
  74. ) {
  75. // equal to old? use old prop
  76. comboProps[key] = oldProps[key]
  77. } else {
  78. comboProps[key] = newProps[key]
  79. anyChanges = true
  80. }
  81. }
  82. for (let key in oldProps) {
  83. if (!(key in newProps)) {
  84. anyChanges = true
  85. break
  86. }
  87. }
  88. return { anyChanges, comboProps }
  89. }