Hyperapp: multiple `app()`s / component approach / return dom

Created on 31 Jan 2017  路  10Comments  路  Source: jorgebucaran/hyperapp

So, it is just amazing lib. A was working on some idea like that, code name mitak ;d Based on events with just router, pub/sub system. For now it is 450bytes gzip. But yea, anyway.

So the problem of return nothing just bumped while I tried to make a Todo List in components way.

So lets get started. We have 3 app()s - TodoItem, TodoList and main.

  • main - main entry, place for header & footer for example
  • TodoItem - component for each todo, e.g. <li></li>
  • TodoList - component holding all TodoItems, actions and view which is just like <ul>TodoItem()</ul>

main

const { app, html } = require('hyperapp')

const main = app({
  // root: document.body,
  model: {
    title: 'Todo List Example',
    link: 'https://github.com/hyperapp/hyperapp'
  },
  view: (state) => html`<main id="HyperApp">
    <h1>${state.title}</h1>
    ${TodoList()}
    <footer>Powered by <a data-no-routing href="${state.link}">HyperApp</a></footer>
  </main>`
})

TodoList

const TodoList = () => app({
  model: {
    todos: [],
    count: 0,
    input: '',
    placeholder: 'Add new todo'
  },
  update: {
    toggle: (state, data) => ({
      todos: state.todos.map((item) => {
        return data.id === item.id
          ? Object.assign({}, item, { done: !data.done })
          : item
      })
    }),
    remove: (state, data) => ({
      todos: state.todos.map((todo) => todo.id !== data.id)
    }),
    add: (state) => ({
      todos: state.todos.concat({
        id: state.count++,
        done: false,
        text: state.input
      })
    }),
    input: (state, data) => ({ input: data.value })
  },
  view: (state, action) => html`<section>
    <ul>${state.todos.map((item) => TodoItem(item, action))}</ul>
    <p>
      <input
        class="add"
        type="text"
        onkeyup=${e => e.keyCode === 13 ? action.add() : ''}
        oninput=${e => action.input({ value: e.target.value })}
        placeholder=${state.placeholder}
      />
      <button onclick=${action.add}>add</button>
    </p>
  </section>`
})

TodoItem

const TodoItem = (state, actions) => app({
  model: state,
  update: actions,
  view: (item, action) => html`<li onclick=${e => action.toggle(item)}>${item.text}</li>`
})

All is okey, but it adds Todo to DOM body two times

2017-01-31-14 53 55_1280x1024_scrot

Passing opts.root seems to not deal with that problem.

The only thing that I changed to the core source code, is to return node from app function.

Discussion Feature Wontfix

Most helpful comment

@tunnckoCore @tzellman @evgenykochetkov Here's a TodoMVC implementation using HyperApp.

screen shot 2017-02-01 at 23 54 37

All 10 comments

So, it should not "auto mount". Maybe would be cool to return a function that when called to append to body, or that function can accept selector where app to be mounted

If you set the root of Todo to document.createElement("div") it won't double-render the Todo component. I am still looking into the TodoItem rendering...

Yea, it seems it work, but not work for nested components (or i dont know how to call it). Nested component (here TodoItem) should know who is the parent. It is easy to document.createElement('div') and pass that div to opts.root of Todo, and later pass that same div to TodoItem and set it as its opts.root but it seems it not work.

I just breifly read the source code, so I might be wrong, but I don't think that app is intended for creating components. It's more like program in Elm's Html.App

Also, why not define TodoItem like this

const TodoItem = (item, action) => html`<li onclick=${e => action.toggle(item)}>${item.text}</li>`

Clarification: I just breifly read hyperapp's source code
edit2: here is an example in jsbin http://jsbin.com/tomusut/edit?js,output

I know that. And basically it could be possible to be used for components if change some bytes here and there.

I actually don't like components way and things like that and choo are good and enough for me. Just started to think how it can be done, because a comments in reddit.

Oh, sorry, I was not aware of discussion on reddit.

edit: I think I found it. Very interesting, thank you!

@evgenykochetkov @tunnckoCore

I don't think that app is intended for creating components. It's more like program in Elm's Html.App

Correct.

And basically it could be possible to be used for components if change some bytes here and there.

Like I said on the Reddits, thank you for bringing this up. I think we may be onto something here.

@tunnckoCore @tzellman @evgenykochetkov Here's a TodoMVC implementation using HyperApp.

screen shot 2017-02-01 at 23 54 37

This is as far I think we can go with the current implementation of HyperApp.

It's not just a matter of implementation, it's also a goal of the project to remain close to the Elm Architecture and use a single model for the entire application kind of approach.

Docs have been updated to indicate this as well.

Summary

The original idea here was to make the return value of the app function a valid node type and make apps composable that way. This is not supported, but that doesn't mean you can't create multiple _different_ apps and communicate with each other using whatever means possible, usually wired actions in V1 or the upcoming subscriptions API in V2.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

joshuahiggins picture joshuahiggins  路  4Comments

dmitrykurmanov picture dmitrykurmanov  路  3Comments

jamen picture jamen  路  4Comments

jscriptcoder picture jscriptcoder  路  4Comments

guy-kdm picture guy-kdm  路  4Comments