{"size": 2656, "ext": "js", "max_stars_repo_path": "src/platforms/react-vue/observer.js", "max_stars_repo_name": "emtudo/vue-native-core", "max_stars_repo_stars_event_min_datetime": "2017-06-15T23:09:41.000Z", "max_stars_repo_stars_event_max_datetime": "2022-03-08T11:24:12.000Z", "max_issues_repo_path": "src/platforms/react-vue/observer.js", "max_issues_repo_name": "emtudo/vue-native-core", "max_issues_repo_issues_event_min_datetime": "2017-06-18T14:27:23.000Z", "max_issues_repo_issues_event_max_datetime": "2021-12-27T17:34:30.000Z", "max_forks_repo_path": "src/platforms/react-vue/observer.js", "max_forks_repo_name": "emtudo/vue-native-core", "max_forks_repo_forks_event_min_datetime": "2017-06-16T05:14:45.000Z", "max_forks_repo_forks_event_max_datetime": "2022-02-19T22:41:42.000Z"}
{"max_stars_count": 1323, "max_issues_count": 13, "max_forks_count": 81, "avg_line_length": 28.8695652174, "max_line_length": 149, "alphanum_fraction": 0.6826054217}
/**
 * Reference to mobx https://github.com/mobxjs/mobx-react-vue/blob/master/src/observer.js
 */

import React from 'react'
import Watcher from 'core/observer/watcher'

export default function observer (componentClass) {
  if (typeof componentClass === 'function' &&
    (!componentClass.prototype || !componentClass.prototype.render) && !componentClass.isReactClass && !React.Component.isPrototypeOf(componentClass)
  ) {
    class ObserverComponent extends React.Component {
      render () {
        return componentClass.call(this, this.props, this.context)
      }
    }
    ObserverComponent.displayName = componentClass.displayName || componentClass.name
    ObserverComponent.contextTypes = componentClass.contextTypes
    ObserverComponent.propTypes = componentClass.propTypes
    ObserverComponent.defaultProps = componentClass.defaultProps
    return observer(ObserverComponent)
  }

  if (!componentClass) {
    throw new Error("Please pass a valid component to 'observer'")
  }

  const target = componentClass.prototype || componentClass
  mixinLifecycleEvents(target)
  return componentClass
}

function mixinLifecycleEvents (target) {
  for (const key in lifecycleMixin) {
    if (key === 'shouldComponentUpdate' &&
      typeof target.shouldComponentUpdate === 'function') {
      continue
    }
    patch(target, key)
  }
}

const lifecycleMixin = {
  componentWillMount () {
    const cb = this.forceUpdate.bind(this)
    const render = this.render.bind(this)
    const watcher = new Watcher({ _watchers: [] }, render, cb, { lazy: true })
    this.render = watcher.get.bind(watcher)
    watcher.lazy = false
    watcher.run = cb
    this.$vuewatcher = watcher
  },
  componentWillUnmount () {
    this.$vuewatcher.teardown()
  },
  shouldComponentUpdate (nextProps, nextState) {
    if (this.state !== nextState) {
      return true
    }
    return isObjectShallowModified(this.props, nextProps)
  }
}

function patch (target, funcName) {
  const base = target[funcName]
  const mixinFunc = lifecycleMixin[funcName]
  target[funcName] = !base ? function () {
    return mixinFunc.apply(this, arguments)
  } : function () {
    mixinFunc.apply(this, arguments)
    return base.apply(this, arguments)
  }
}

function isObjectShallowModified (prev, next) {
  if (prev == null || next == null || typeof prev !== 'object' || typeof next !== 'object') {
    return prev !== next
  }
  const keys = Object.keys(prev)
  if (keys.length !== Object.keys(next).length) {
    return true
  }
  let key
  for (let i = keys.length - 1; i >= 0; i--) {
    key = keys[i]
    if (next[key] !== prev[key]) {
      return true
    }
  }
  return false
}
