Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
ui-component-library / src / observable.tsx
Size: Mime:
import { observable, action } from 'xmobx/mobx'

// # example
// 1. observable

class EhState {
  // isNotObserved = true
  @observable isVisible: boolean = false
}

// 2. action


// const list = 

class EhStateWithAction {
  @observable isVisible: boolean = false

  @action
  toggle() {
    this.isVisible = !this.isVisible
  }
}


// === lifecycle ===
class Uncommon extends React.Component {
  // error boundary is just this
  componentDidCatch() {
    // error
  }
  componentWillReceiveProps() {
    //
  }

  shouldComponentUpdate() {
    // do not need
    return false
  }

  componentWillUpdate() {
    //
  }
  render() {
    return 'will, render, did'
  }
  componentDidUpdate() {
    //
  }
}


// how mobx works sudo code
const tracking = {
  [state.isVisible]: []
}
let currentlyListening = undefined
const listeners = []

const secretState = {
  get isVisible() {
    if (currentlyListening) {
      listeners.push(currentlyListening)
    }
    //
    return state.isVisible
  },
  set isVisible(value) {
    // first it checks if it is the same value, so it doesn't nofiy extra

    const change = {
      key: 'isVisible',
      value: value,
      oldValue: this.$mobxSecret.value,
    }
    this.$mobxSecret.value = value

    if (listeners.length) {
      listeners.forEach(listener => listener(change))
    }
  }
}

@observer
class SmartObserving extends React.Component {
  _render() {
    console.log(state.isVisible)
    return 'eh'
  }
  render() {
    currentlyListening = this
    const rendered = this._render()
    currentlyListening = undefined
    return rendered
  }
}


// ===

const state = new EhStateWithAction()

// 3. observer

// ===
// - component
import React from 'react'
import { observer } from 'xmobx/mobx-react'

@observer
class Eh extends React.Component {}

// ===
// - observing as a fn
import { observe } from 'xmobx/mobx'

observe(state, () => {
  console.log('every time state changes')
})

observe(state, 'isVisible', () => {
  console.log('every time state.isVisible changes')
})

// only 1
const singleState = state

const countState = observable({
  updateCount: 0,
  increment() {
    // void
  },
})
countState.increment = action(() => {
  countState.updateCount += 1
})


// @observer
class EhObserverExample extends React.Component {
  componentDidMount() {
    const onInterval = () => {
      // turn on and off every second
      // like a kid who discovered a light switch for the first time
      state.toggle()
    }
    setInterval(onInterval, 1000)

    observe(state, () => {
      countState.increment()
      this.forceUpdate()
    })
  }

  render() {
    return <span>updated: {countState.updateCount}</span>
  }
}

class Lifecycle extends React.Component {

  componentDidMount() {
    // happens 1x after render in the browser
    // updates to things should happen here
    // after this, it will update 1x
  }
  componentWillUnmount() {
    // clean up when it's no longer used
    // example, when you go from 1 page to another, things unmount
    // always stop listening to things like click events here
  }

  render() {
    return 'known'
  }

  componentWillMount() {
    // this is used for server side rendering and rehydration
    // since it happens 1x on server & 1x in browser
  }
}
// ========= multi ===

function createMultiState() {
  const newState = new EhStateWithAction()
  return newState
}

// now we can have 10, and they all have their own
// class MultiStateObserver extends React.Component {
//   // state = createMultiState()
//   constructor(...args) {
//     super(...args)
//     this.thingToObserve = new EhStateWithAction()
//   }
// }

class MultiStateObserver extends React.Component {
  static defaultProps = {
    // @note - you can't have a getter on React.Prop
    //  so it will be called by react
    get state() {
      return new EhStateWithAction()
    },
  }
}

// would never call the getter
// const eh = ''
// <MultiStateObserver state={eh} />

// would call the getter
// =>
// props = Object.freeze({
//   state: new EhStateWithAction()
// })


// === how defaultProps works ===


// @todo console.table console.group
function isUniq(value, index, arr) {
  console.assert(Array.isArray(arr), '3rd arg is the instance')

  const firstIndex = arr.indexOf(value)
  const isFirst = firstIndex === index

  // console.table([
  //   ['value', value],
  //   ['isFirst', isFirst],
  //   ['firstIndex', firstIndex],
  // ])
  // console.log('\n\n\n')

  return isFirst
}
// ['a', 2, 'a', 'b'].filter(isUniq)

// const list = ['a', 2, 'a']
// list.filter(isUniq)

function keys(obj) {
  const names = Object.getOwnPropertyNames(obj)
  const descriptors = Object.getOwnPropertyDescriptors(obj)
  const renamedDescriptors = Object.keys(descriptors)
  const symbols = Object.getOwnPropertySymbols(obj)
  const objKeys = Object.keys(obj)
  const list = []

  // eslint-disable-next-line
  // tslint:disable forin
  for (const index in obj) {
    list.push(index)
  }

  return list
    .concat(objKeys)
    .concat(names)
    .concat(renamedDescriptors)
    .concat(symbols)
    .filter(isUniq)
}

function mergePropsAndDefaultProps(props, defaultProps) {
  // make a copy of props
  const frozenProps = Object.assign({}, props)

  keys(defaultProps).forEach(key => {
    // 1. if props that are passed in do not have this key
    // 2. calling hasOwnProperty WILL NOT TRIGGER A GETTER
    if (!Object.prototype.hasOwnProperty.call(props, key)) {
      console.debug('does have property: ', key)
      // THIS WILL TRIGGER ANY GETTERS
      frozenProps[key] = defaultProps[key]
    } else {
      console.debug('does not have property: ', key)
    }
  })

  Object.freeze(frozenProps)
  return frozenProps
}

function example() {
  const props = {
    eh: true,
  }
  const defaultProps = {
    eh: false,
    moose: true,
    [Symbol.toPrimitive](type) {
      console.debug('(default)Props.toPrimitive')
      if (type === 'number') {
        return -42
      } else {
        // also has options of type = 'string' | 'number' | 'default' | undefined
        return 'eh'
      }
    },
    get canada() {
      console.info('accessing defaultProps.canada')
      return 'eh'
    },
  }

  const proto = {
    protoProp: 0x1,
  }
  Object.setPrototypeOf(defaultProps, proto)

  Object.defineProperty(defaultProps, 'hidden', {
    configurable: true,
    enumerable: false,
    value: 10,
  })

  return mergePropsAndDefaultProps(props, defaultProps)
}
example()

// <MultiStateObserver />
// class MultiStateObserver extends React.Component {
//   constructor(props) {
//     super(props)
//     console.assert(
//       Object.isExtensible(props) === false,
//       'props is frozen, cannot change'
//     )
//     if (props.state === undefined) {
//       this.state = new EhStateWithAction()
//     } else {
//       this.state = props.state
//     }
//   }
// }