Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
scalajs-reactで作るフロントエンド / Frontend With scalajs...
Search
yuiwai
September 30, 2019
Programming
610
3
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
scalajs-reactで作るフロントエンド / Frontend With scalajs-react
yuiwai
September 30, 2019
More Decks by yuiwai
See All by yuiwai
Lagomに学ぶマイクロサービス / Learn Microservice with Lagom
yuiwai
0
880
Scalaで作るカジュアルゲーム
yuiwai
1
590
Other Decks in Programming
See All in Programming
5分で問診!Composer セキュリティ健康診断
codmoninc
0
1.1k
PostgreSQL 18で考えるUUID主キー
kazuhiro1982
0
480
Laravel Boostに学ぶ、AIにPHPを書かせる技術 〜OSSの実装から蒸留するエージェント制御の王道〜
kentaroutakeda
3
720
改善しないと、タスクが回らない。 “てんこ盛りポジション” を引き継いだ情シスの、入社3ヶ月の業務改善録
krm963
0
270
バグを直したら useEffect が消えた
colorful12
3
630
php-fpmのプロセスが枯渇した日-調査・対処・そして本当にやるべきだったこと-
shibuchaaaan
0
310
実装をデザインガイドラインに追従させるための取り組み / 260731-dip-mosh-design-system
dachi023
0
5k
属人化した知識を、 AIが辿れる地図にする
pkshadeck
PRO
1
190
進化を続けるGo toolsの現在地 / The Current State of Ever-Evolving Go Tools
hond0413
0
240
How I Won Prize Money at a Hackathon Using Codex and Symphony Alpha
yasei_no_otoko
0
110
Augmenting AI with the Power of Jakarta EE
ivargrimstad
0
640
Claude Code全社展開のためにやったことn選~プラグイン302個・コミッター271人を支えるために~
kenchan
5
1.6k
Featured
See All Featured
How to Get Subject Matter Experts Bought In and Actively Contributing to SEO & PR Initiatives.
livdayseo
0
170
Effective software design: The role of men in debugging patriarchy in IT @ Voxxed Days AMS
baasie
0
480
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
123
22k
Introduction to Domain-Driven Design and Collaborative software design
baasie
1
940
The Director’s Chair: Orchestrating AI for Truly Effective Learning
tmiket
1
270
Art, The Web, and Tiny UX
lynnandtonic
304
22k
The Straight Up "How To Draw Better" Workshop
denniskardys
239
140k
svc-hook: hooking system calls on ARM64 by binary rewriting
retrage
2
490
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
31
3.3k
sira's awesome portfolio website redesign presentation
elsirapls
0
330
Unlocking the hidden potential of vector embeddings in international SEO
frankvandijk
0
900
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
201
75k
Transcript
scalajs-reactで作る フロントエンド Yuichiro.iwai 2019/09/30 - Fun Fun Functional (3)
自己紹介 岩井 雄一郎(SUGAR株式会社) Scalaをこよなく愛する37歳、道産子、2児の父 長らくソシャゲ業界でサーバサイドの開発をしてました。 4月からSUGARで、主にAndroidの開発をしています。 趣味はダーツ、ギター、将棋
今日のお話 このたび、フロントエンド(管理画面的なもの)を書くかも?ということになりまし て、かねてより愛用していたScala.jsで、Reactを利用するアプローチについて調 査しましたので、その概念をご紹介したいと思います。 (個人的に、もっとScala.jsが広まればいいな、と願っており、その宣伝も兼ねて おりますこと、ご了承ください)
Scala.jsとは? • Scalaで書いてJSにコンパイルされる、いわゆるAltJSの一種 • Scalaで書いたコード+一部のJavaライブラリ*が動く • Scala.js用にビルドされたScalaライブラリが利用可能 https://github.com/scala-js/scala-js *Scalaの動作の為に必要な Java依存部分を、Scala.js用に書いたもの(ライセンス的な)
Reactとは? • Facebook社が開発したJS向けのUIライブラリ • 状態とViewを分離し、仮想DOMを用いて効率的な描画を実現 • コンポーネントベース ◦ 再利用可能で副作用の無い小さな単位に切り分ける https://github.com/facebook/react/
Reactとは? State VDOM HTML ある状態の入力に対して、 VDOMが一意に決まり、結果として HTMLがレンダリングされる
Reactとは? State VDOM HTML modified! 状態の変化が通知されると、 VDOMが更新されて
Reactとは? State VDOM HTML modified! diff 以前のVDOMとの変更差分が算出され、それが HTMLへと反映される
scalajs-reactとは? • Scala.js用のReactライブラリ • Scalaで書きやすいような工夫がなされている • 副作用を局所化、型安全、Functionalなアプローチ • Routerなどの拡張も含んでいる https://github.com/japgolly/scalajs-react
scalajs-reactで扱う 主要な概念を見ていきます
State • Immutableなデータ構造 ◦ 更新時は、新しいStateを作り直す ◦ case classとの相性が非常に良い • Component内の動的な性質を保持する
◦ ユーザの操作に応じて変化する値 ◦ API通信など外部から取得した値 ◦ 時間経過で随時変化する値 ...など • 基本的には最上位の Componentにのみ持ちたい(次ページへ) case class State(wallet: Wallet) { def charge(amount: Point): State = copy(wallet = wallet.charge(amount)) } case class Wallet(balance: Point) { def charge(amount: Point): Wallet = copy(balance = balance.add(amount)) } case class Point(value: Long) extends AnyVal { def add(that: Point): Point = ... }
Root以外のComponentがStateを持つべきか? • 基本的には上位Componentから受け取ったPropsにのみ依存し、結果を決めたい ◦ データの流れを単方向にし、副作用を排除することで、再利用しやすくなる ◦ 下位Componentで変化したStateを上位に同期する流れは、構造が複雑化する • ただし、そのComponent内で完結し、揮発してしまっても構わない Stateなら、各Componentで
持った方が素直に書けると考えています ◦ 例えば、編集中のフォームのデータ、その画面内だけで有効な設定など
Props • Immutableなデータ構造 ◦ やはりcase classとの相性が良い • Componentの初期化時に渡される • Componentの静的な性質を保持する
◦ 上流にイベントを伝搬するハンドラ ◦ Globalな設定など ◦ 親Componentから受け継いだ属性 ...など case class Props( wallet: Wallet, // 状態の参照 settings: GlobalSetting, // 何らかの設定など handler: Action => Callback // イベントハンドラ ) // VDOMの中で使う例 (p: Props) <.div( s“残高: ${p.wallet.balance.value}”, <.button( ^.onClick --> p.handler(Charge), “チャージ” ) )
Component • singleton objectとして定義を格納する • StateとPropsを定義 ◦ StateはComponent内で可変 ◦ PropsはComponent内で不変
• Backend(後述)を定義 object WalletComponent { case class Props(...) case class State(...) class Backend(...) { ... } } 定義 Component 初期化 Props 実体
Component Backend • Component定義内にBackendというクラスを作成 ◦ このクラス内の処理が Componentの実体となる • renderメソッドを定義 ◦
State/Propsを受け取りVDOMを返す Props State Backend render() VDOM 状態の入力から、描画への出力を行う、いわば橋 渡し的な存在で、UIライブラリとしての中核を担う。
BackendScope • Backendがコンストラクタに受け取る ◦ このインスタンスを介して Stateを 操作したり、Propsを参照したり • Props/Stateを型パラメータに持つ ◦
BackendScope[Props, State] • renderメソッドの外からState/Propsに アクセスする場合、このインスタンス を経由し、Callbackとして扱う ◦ Callbackが評価されるタイミングで その時点のState/Propsを参照する // bsはBackendScopeのインスタンス bs: BackendScope[Props, State] // 現在のStateを受け取り新しいStateに更新 // modState(f: State => State): Callback bs.modState( s => ...) // bs.propsはPropsの参照を表す // CallbackTo[Props] // // このmapは // map[A](f: Props => A): CallbackTo[A] bs.props.map { p => ... }
階層化されたComponent • Componentは子として別なComponentを 持つことができる • 親から子へは、Propsを通じてデータを 受けわたす • 親のState(もしくはProps)が変化することで 子に変更が伝搬される
Parent Child Props Props State
VDOM • 属性値を持った要素のツリー構造 ◦ 実質、HTMLのタグに相当 • ユーザのインタラクションを イベント(後述)として受け取る // <.xxx(...)
で要素(タグ)を定義 <.div( // ^.xxx := ... で属性を定義 ^.id := “someId”, <.button( // --> イベントハンドラ ^.onClick --> { … }, // 文字列はそのまま子要素扱い “Click Me!” ), // Componentを子要素にする OtherComponent.Props(...).render )
Event(Handler) • クリックやキー入力などユーザ操作で発生 • EventをトリガーにCallback(後述)を返す ハンドラを実装することでリアクション ◦ ハンドラはEventオブジェクトを受け取る こともできる //
以下はVDOMの属性定義の文脈の前提 // -->[A](cb: => CallbackTo[A]): TagMod ^.onClick --> { ... } // ==> はイベントオブジェクトを受け取る // ==>[A](f: Event => CallbackTo[A]): TagMod ^.onKeyDown ==> { e => // ここでpersist()を呼んでおかないと // このCallbackが評価される時点で // 正しいイベントオブジェクトにアクセス // できない場合がある e.persist() … } ※TagModはVDOM中の構成要素として展開可能な型 イベントオブジェクトを受け取るケースでは、Callbackが 遅延評価されることと、イベントオブジェクトが再利用さ れることの兼ね合いで、persistを呼んでおかないと正常 に動作しないという罠が
Callback,CallbackTo[T] • 副作用を包み込む ◦ Stateの書き換え ◦ 外部通信などの非同期処理 ◦ ログ出力やAlertの表示 •
CallbackTo[T]はT型の結果を包んだもの • CallbackはCallbackTo[Unit]へのalias • >>や>>=などで合成できる • 非同期版のAsyncCallback[A]もある val cba: CallbackTo[A] = … val cbb: CallbackTo[B] = … val a2cbb: A => CallbackT[B] = … val asyncCbc: AsyncCallbackTo[C] = ... // シーケンシャルに実行 // >>[B](runNext: CallbackTo[B]): CallbackTo[B] cba >> cbb // >>= はflatMapのalias // >>=[B](f: A => CallbackTo[B]): CallbackTo[B] cba >>= a2cbb // AsyncCallback同士で処理する必要がある // callback.asyncでAyncCallbackに変換 cba.async >> asyncCbc
Component 全体像 React.js scalajs-react HTML VDOM User Backend State Event
Props Initialize View Action render() EventHandler Callback Modify Event
まとめ • scalajs-reactは、Scalaを使ってFunctionalなアプローチでWebフロントエ ンドを書けるソリューションです。 • Scala好き、あるいはScalaに興味があり、フロントエンドもScalaで書いてみ たいという方にはオススメです。 • Scala.jsはWebフロント以外のユースケースもあります! 興味を持っていただけたら、幸いです。
ご清聴ありがとうございました