tunnckoCore / ideas

:notebook: My centralized place for ideas, thoughts and todos. Raw, PoC implementations and so on... :star:
http://j.mp/1stW47C
6 stars 0 forks source link

freaking - state management 2017 #84

Open tunnckoCore opened 6 years ago

tunnckoCore commented 6 years ago

backup. some prototype, kinda working. Final result, final signatures and etc. There are problems with rerendering which can be fixed with event system seen near the middle in #71 using dush and dush-router.

const freaking = (options) => {
  if (typeof options === 'function') {
    options = { render: options }
  }

  let tree = null
  let { effects, reducers, state, events, render } = Object.assign({}, options)

  events = Object.assign({}, events)
  effects = Object.assign({}, effects)
  reducers = Object.assign({}, reducers)

  let hooks = Object.keys(events).reduce((obj, name) => {
    // eslint-disable-next-line
    obj[name.toLowerCase()] = events[name]
    return obj
  }, {})

  hooks = Object.assign(
    {
      onerror: (er) => {
        throw er
      },
      onaction: () => {},
      oneffect: () => {},
      onreducer: () => {},
      onstateupdate: () => {},
      onrender: (view, props) => view(props)
    },
    hooks
  )

  const guard = (fn) => (...args) => {
    try {
      fn(...args)
    } catch (er) {
      hooks.onerror(er)
    }
  }

  let STATE = Object.assign({}, state)
  let actions = Object.keys(
    Object.assign({}, reducers, effects)
  ).reduce((memo, name) => {
    memo[name] = (...args) => {
      guard(hooks.onaction)(name, ...args)

      if (effects[name]) {
        return Promise.resolve()
          .then(() => {
            guard(hooks.oneffect)(name, ...args)
            return effects[name]({ actions }, ...args)
          })
          .catch(hooks.onerror)
      }

      guard(hooks.onreducer)(name, ...args)

      const oldState = Object.assign({}, STATE)
      const newState = reducers[name]({ actions, state: oldState }, ...args)

      STATE = Object.freeze(Object.assign({}, oldState, newState))
      guard(hooks.onstateupdate)(oldState, STATE, ...args)

      return STATE
    }
    return memo
  }, {})

  const _propsFn = (_render) => (props) => {
    props = Object.assign({ actions }, props)

    // todo: should we?
    props.state = Object.assign({}, STATE, props.state)

    if (typeof props.children === 'function') {
      return props.children(props)
    }

    tree = guard(hooks.onrender)(_render, props, tree)

    return tree
  }

  return typeof render === 'function'
    ? _propsFn(render)
    : (_render) => _propsFn(_render)
}

// const { render, html } = require('./lithtml')
const html = require('bel')
const nanomorph = require('nanomorph')

const main = document.querySelector('#app')
const Heading = freaking({
  events: {
    onrender: (view, props, tree) => nanomorph(tree || main, view(props))
  },
  state: {
    username: null
  },
  reducers: {
    changeName: ({ state }) => ({ username: 'hoho' })
  },
  render: ({ actions, state, name }) =>
    html`<div>
      <h1 onclick=${actions.changeName}>
        Hello ${state.username || name}
      </h1>
    </div>`
})

const ele = Heading({ name: 'Charlike' })
console.log('ele', ele)
// nanomorph(main, ele)