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
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
yuiwai
September 30, 2019
Programming
600
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
860
Scalaで作るカジュアルゲーム
yuiwai
1
570
Other Decks in Programming
See All in Programming
【やさしく解説 設計編 #0】DDDのコード、読めるのに分からない人へ
panda728
PRO
1
160
エージェンティックRAGにAWSで入門しよう!
har1101
9
1.9k
Webフレームワークの ベンチマークについて
yusukebe
0
190
エンジニアにデザインハーネスを 〜デザインプロセスを規定するためのハーネス〜 / Design harness from an engineer's perspective
rkaga
1
540
Semantic Version 単位で戦略を柔軟に変えて、パッケージアップデートを自動化する
daitasu
1
330
Language Server 使ってる? 〜VSCode と Zed の場合〜 / Are you using a Language Server? ~For VS Code and Zed~
handlename
0
820
SREは、MCPとSRE Agentをこう使え!
kazumax55
0
130
正しくソフトウェアを作る、前提を疑うための認知の視点 / doubt-premise
minodriven
21
7.2k
才能?センス?知らん、 続けたもん勝ちだ。-- 結婚・出産・癌を越えてなお、私がプロダクトを創り続ける理由
16bitidol
2
640
Spec Driven Development | AI Summit Lisbon
danielsogl
PRO
0
230
分散システム、なんですぐ死んでしまうん?耐障害性を高めたいあなたのためのレジリエンスパターン入門
mshibuya
2
350
過去最大のMCPアップデート! 2026-07-28 RC版の謎に迫る
licux
6
430
Featured
See All Featured
How to Ace a Technical Interview
jacobian
281
24k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
133
19k
How to Talk to Developers About Accessibility
jct
2
270
Fashionably flexible responsive web design (full day workshop)
malarkey
408
66k
How to optimise 3,500 product descriptions for ecommerce in one day using ChatGPT
katarinadahlin
PRO
1
3.7k
Designing for Timeless Needs
cassininazir
1
270
職位にかかわらず全員がリーダーシップを発揮するチーム作り / Building a team where everyone can demonstrate leadership regardless of position
madoxten
62
55k
Paper Plane (Part 1)
katiecoart
PRO
0
9.5k
Utilizing Notion as your number one productivity tool
mfonobong
4
340
HU Berlin: Industrial-Strength Natural Language Processing with spaCy and Prodigy
inesmontani
PRO
0
430
Marketing to machines
jonoalderson
1
5.5k
Abbi's Birthday
coloredviolet
3
8.4k
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フロント以外のユースケースもあります! 興味を持っていただけたら、幸いです。
ご清聴ありがとうございました