21
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Hyperapp試すためにTodoアプリ作った

Last updated at Posted at 2018-01-29

年末年始あたりにHyperapp関連の記事を沢山見かけたので試してみました

image.png

使ったのはHyperapp,バンドルにはparcel, ホスティングにはNetlifyを使った

これが成果物

Hyperapp

state, action, view だけのシンプルな感じはすぐに馴染めて楽しかった。
いきなりコード見せると(プログラミング苦手なのでレビューお願いします、もっといい方法とか🙇)

index.js
import { h, app } from 'hyperapp'
import picostyle from 'picostyle'

const ps = picostyle(h)

const STORAGE_KEY = 'MyNameIsBond'
const WEEK = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
const MONTH = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']

const fetchTodos = () => {
  return JSON.parse(window.localStorage.getItem(STORAGE_KEY)) || []
}

const today = new Date()
const dayName = () => {
  return WEEK[today.getDay()]
}

const todayDate = () => {
  return `${MONTH[today.getMonth()]} ${today.getDate()}, ${today.getFullYear()}`
}

const state = {
  todoValue: '',
  todos: fetchTodos(),
  dayName: dayName(),
  todayDate: todayDate()
}

const actions = {
  onInput: value => state => {
    state.todoValue = value
  },

  addTodo: () => state => {
    if (!state.todoValue.length) return
    state.todos.push({
      id: state.todos.length,
      value: state.todoValue,
      completed: false
    })
    window.localStorage.setItem(STORAGE_KEY, JSON.stringify(state.todos))
    state.todoValue = ''
    return state.todos
  },

  removeTodo: id => state => {
    state.todos = state.todos.filter(todo => todo.id !== id)
    window.localStorage.setItem(STORAGE_KEY, JSON.stringify(state.todos))
    return state.todos
  },

  handleCheckbox: index => state => {
    state.todos[index].completed = !state.todos[index].completed
    window.localStorage.setItem(STORAGE_KEY, JSON.stringify(state.todos))
    return state.todos
  },
}

const view = (state, actions) => {
  const Wrapper = ps('main')({
    height: '100%',
    display: 'flex',
    flexDirection: 'column',
    justifyContent: 'center',
    alignItems: 'center',
    textAlign: 'center',
  })

  ~~~ css 省略 ~~~

  return(
    <Wrapper>
      <Content>
        <Week>{ state.dayName }</Week>
        <Date>{ state.todayDate }</Date>
        <TodoLists>
        {
          state.todos.map((todo, index) => {
            return(
                <TodoListsItem
                class={todo.completed ? "completed" : ""}
                >
                <span class="todo-value">{todo.value}</span>

                  <Checkbox
                    type="checkbox"
                    checked={todo.completed}
                    onclick={() => actions.handleCheckbox(index)}
                  ></Checkbox>

                {/* <span
                    class="delete-button"
                    onclick={() => actions.removeTodo(todo.id)}
                  >×</span>
                */}
                </TodoListsItem>
            )
          })
        }
        </TodoLists>
        <TodoInput
          type="text"
          placeholder="What needs to be done?"
          value={state.todoValue}
          oninput={e => actions.onInput(e.target.value)}
          onkeydown={e => e.keyCode === 13 ? actions.addTodo() : ''}
          oncreate={e => e.focus()}
        />
      </Content>
    </Wrapper>
  )
}

export const main = app(state, actions, view, document.body)

シンプルなアプリなので説明する所はあまりないかも
Todo removeのコードはあるけど、UIが定まらなくてコメントアウトしちゃった
個人的にjsx書くの初めてだったので、色々勉強になった。(気になったのはみんなjsxの中にロジックとかガンガン書いてるんだけど、jsxでは普通?)
やっぱりもっとJS勉強して上手くならなきゃ...😰

Parcel, Netlify, おまけ

Parcel

image.png

ParceとHyperappの連携はこちらの記事を参考にさせてもらった
ほんとにお手軽にバンドルできて感動した🕺

ひとつだけ詰まったのはProduction用のbuild
parcel build index.html だとデフォルトの dist ディレクトリにバンドルされてJS, CSSのパスが /dist/foobar.js になる。その状態でデプロイしちゃってそんなのねーよ!って怒られた。
Production buildは parcel build index.html --public-url ./ が正解みたい

Netlify

image.png

めっちゃ簡単、死ぬほど簡単
全部ブラウザで完結するのでHerokuより簡単だと思う

なかでもPrerenderをやってくれる機能があったので使いたかったけど有料プランからだったので諦めた、お金持ちになったら払いたい

おまけ(picostyle)

スタイリングにはpicostyleを使った
こちらの記事を読んでHyperapp使うならこれなんだなって勝手に解釈した

今までVueのsingle file compenentしか使ってなかったのでCSS in JSは新鮮だった。
特に悩むことはなかったけど、CSS in JS特有の普通のCSSの書き方から逸脱するのは結構辛かった
SketchかZeplinのデータそのままコピペが不可能でしんどいなーって感想
ex) marginRight: '16px' => margin-right: 16px;
[styled-components](https://github.com/styled-com
ponents/styled-components)はそこら辺普通のシンタックスでいけるのでpicostyleも対応してくれるとありがたいなぁ🤔

感想

自分みたいなレベルめた低いやろうでも理解はできました
なのでJavaScriptを学んでなんか簡単なアプリケーション作りたい!っていう人におすすめな気がします!
Vueとか色んな所で簡単!って言われるけどなんだかんだVue特有の何かみたいなのは存在するのでやっぱりハードルは高い気が前々からしてました。

Hyperappはその特有さがほぼ0。
かなりとっつき易いです。

このTODOアプリもちょっとずつ更新していこうと思います(アイテム消したり、コンプリートしたものだけのソートとか、リマインダー機能とか)

21
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?