anthonyshort / deku

Render interfaces using pure functions and virtual DOM
https://github.com/anthonyshort/deku/tree/master/docs
3.41k stars 131 forks source link

Deku Override #417

Open iazel opened 8 years ago

iazel commented 8 years ago

Hello, I've made a generic List component, however to do it I had to replace a large portion of Deku, more precisely the createElement and updateElement. To have a generic List that accept any kind of component, I need to wrap any actions dispatched by its children and to do this, I need two wrap the dispatch itself. Therefore I've added a new optional property to the vnode: override. For now I used it to override the dispatch but it could be used for any parts of the model.

During the HTML element creation, I check if the vnode want to override something or not. The addons per se is very small:

function createThunk(vnode, path, dispatch, context) {
  /* ... head ... */
  let model = overrideModel(vnode, {
    children,
    props,
    path,
    dispatch,
    context
  })
 /* ... tail ... */
}

// same thing for updateThunk

function overrideModel(vnode, model) {
  if(typeof vnode.override !== 'object')
    return model

  const override = vnode.override
  Object.keys(override).forEach((k) => {
    model[k] = override[k]( model[k] )
  }) 
  return model
}

Then I can override dispatch with:

vnode.override.dispatch = (dispatch) => (action) => wrap(action)

However I had to replace the entire dom and createApp, because this two functions are deeply nested.

You can see the results of this work at this repo List of Counters.

I don't know if it's good to implement this kind of overriding, however would be great to have the possibility to easily replace the create and update functions. I'm thinking on it...