Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
scalajs-reactで作るフロントエンド / Frontend With scalajs...
Search
yuiwai
September 30, 2019
Programming
620
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
890
Scalaで作るカジュアルゲーム
yuiwai
1
590
Other Decks in Programming
See All in Programming
Omarchy Tokyo やると聞いて UMPC 買ってセットアップしてきた
mtsmfm
0
150
モバイル交通系ICへのチャージ実例から考える、クロスプラットフォーム開発におけるiOS実機テスト設計とCI運用
yusuga
1
530
Augmenting AI with the Power of Jakarta EE
ivargrimstad
0
260
thread_parallel_with_free-threaded_Python_and_NumPy.pdf
riku_sakamoto
0
350
AI が書く Go コードの品質を劇的に向上させる Linter: “declscope”
mpyw
0
380
Workers Cache を知る
syumai
0
170
Augmenting AI with the Power of Jakarta EE
ivargrimstad
0
280
[GoCon2026] When Goroutines Are Not Enough: Runtime Locality in High-Throughput Go
takehaya
6
2.4k
Everything will be SERVERLESS — 信じて運用した10年の経験値 / Everything Will be Serverless — Lessons Learned from 10 Years of Operational Experience
seike460
PRO
1
430
変化を抱擁するドキュメントの作り方 - ビジネスルール駆動開発がもたらす、コードとの新しい関係
ioki
2
220
UnityでSystem.Net.WebSocketsなWebSocketサーバが動かないのでUnity Monoのコードを覗いてみた / about implementing websocket server with unity mono
drumath2237
1
290
巨大モノリシックアプリ モダン化大作戦
ktcryomm
1
1.1k
Featured
See All Featured
Unsuck your backbone
ammeep
672
58k
Navigating Team Friction
lara
192
16k
Designing for Timeless Needs
cassininazir
1
480
Introduction to Domain-Driven Design and Collaborative software design
baasie
1
990
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
508
140k
Measuring Dark Social's Impact On Conversion and Attribution
stephenakadiri
2
280
Measuring & Analyzing Core Web Vitals
bluesmoon
9
1k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
230
23k
Navigating Algorithm Shifts & AI Overviews - #SMXNext
aleyda
1
1.6k
Lightning talk: Run Django tests with GitHub Actions
sabderemane
0
260
It's Worth the Effort
3n
188
29k
How to Get Subject Matter Experts Bought In and Actively Contributing to SEO & PR Initiatives.
livdayseo
0
200
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フロント以外のユースケースもあります! 興味を持っていただけたら、幸いです。
ご清聴ありがとうございました