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
イカリング2におけるシングルページアプリケーション
Search
cockscomb
October 02, 2017
Programming
7.8k
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
イカリング2におけるシングルページアプリケーション
cockscomb
October 02, 2017
More Decks by cockscomb
See All by cockscomb
はてなアカウント基盤 State of the Union
cockscomb
1
1.6k
jq at the Shortcuts
cockscomb
1
2.1k
GraphQL放談
cockscomb
4
2.2k
GraphQL Highway
cockscomb
28
8.9k
吉田を支える技術
cockscomb
0
2.6k
コーポレートサイトを静的化してAmplify Consoleにデプロイする
cockscomb
0
3.5k
ユーザインターフェイスと非同期処理
cockscomb
5
2.1k
GUIアプリケーションの構造と設計
cockscomb
10
10k
あなたの知らない UIKit の世界 — UITableView に UITextView を置きたい
cockscomb
1
7.7k
Other Decks in Programming
See All in Programming
動画プレイヤーはなぜカクつくのか 〜Flutterのレンダリングとネイティブの境界を解剖する〜
naruogram
0
330
学びを記事・スライド・Xへ高速展開する― AI-assisted Learning Loopで回すコンテンツ生成術
ochtum
0
200
小さなアプリを作って公開するまで
onozaty
0
150
[JA] Domain Modeling with Vanilla Rails: 「操作」から再考するRailsの設計論
yasaichi
4
1.8k
社内AIエージェント「Askワンバン」における コストチューニングの取り組み
t0yohei
0
170
AIが実装を担う時代の「技術設計」と「チームマネジメント」
kamina_zzz
2
240
AWS CDKを理解するために公式の定義を深掘って解説してみる / Understanding AWS CDK by Digging into Its Official Definition
akihisaikeda
3
290
Spec-Driven Development - Why Vaadin Is the Perfect Fit
simas
PRO
0
240
FactoryBotをやめればRSpecは速くなるのか?
yuta_onishi_97
0
1.7k
AIがコードを書いてくれる時代、我々は何を確かめるのか
yosuke_furukawa
PRO
13
5.8k
[DroidKnights 2026] Workflow AX: From Auto-Documented Policies to E2E Testing
raeminkang
0
540
Augmenting AI with the Power of Jakarta EE
ivargrimstad
0
210
Featured
See All Featured
Stop Working from a Prison Cell
hatefulcrawdad
274
21k
技術選定の審美眼(2025年版) / Understanding the Spiral of Technologies 2025 edition
twada
PRO
121
130k
Discover your Explorer Soul
emna__ayadi
2
1.3k
Darren the Foodie - Storyboard
khoart
PRO
4
4.1k
Prompt Engineering for Job Search
mfonobong
0
580
Mozcon NYC 2025: Stop Losing SEO Traffic
samtorres
1
600
Building Experiences: Design Systems, User Experience, and Full Site Editing
marktimemedia
1
660
svc-hook: hooking system calls on ARM64 by binary rewriting
retrage
2
670
Writing Fast Ruby
sferik
630
63k
The Invisible Side of Design
smashingmag
301
52k
AI Search: Implications for SEO and How to Move Forward - #ShenzhenSEOConference
aleyda
1
1.4k
WENDY [Excerpt]
tessaabrams
14
40k
Transcript
ΠΧϦϯάʹ͓͚Δ γϯάϧϖʔδΞϓϦέʔγϣϯ
id:cockscomb Ճ౻ਘथ גࣜձࣾͯͳ γχΞΞϓϦέʔγϣϯΤϯδχΞ ΠΧϦϯάͷ5FDI-FBE
/JOUFOEP
ΠΧϦϯά w /JOUFOEP4XJUDI0OMJOFΞϓϦ෦ͷαʔϏε w 4QMBUPPOͷϓϨΠσʔλΛݟΔ͜ͱ͕Ͱ͖Δ
࠾༻ٕज़ w ϑϩϯτΤϯυ41" w 5ZQF4DSJQU w 3FBDU 3FEVY w ཪଆʹΦʔέετϨʔγϣϯͱͯ͠ͷ"1*αʔόʔ
w 1FSM w %PDLFSͰಈ͍͍ͯΔ
લఏ w ͳΜͰͰ͖ΔνʔϜ w 8FCΞϓϦέʔγϣϯ w J04"OESPJEͷωΠςΟϒΞϓϦ w 41"ॳΊͯ w
σβΠφʔ͕3FBDU$PNQPOFOUΛ৮ΕΔ
w ٕज़બఆ w 3FBDUͱ3FEVYʹΑΔεςʔτϑϧΞϓϦέʔγϣϯ w 3FEVY4BHB w 8FCϖʔδͱͯ͠ͷ41"
ٕज़બఆ
41"ʹ͢Δཧ༝ w /JOUFOEP4XJUDI0OMJOFΞϓϦͷαʔϏε w ΞϓϦʹظ͞ΕΔϦονͳମݧ w J04"OESPJEͷ8FC7JFXͰදࣔͰ͖ΕΑ͍
41"ʹ͢Δཧ༝ w αʔϏεͷಛੑ w ࠶๚͕ଟ͍ ˠΫϥΠΞϯταΠυΩϟογϡͷޮՌ͕ߴ͍ w 17ηογϣϯൺ͕େ͖͍ ˠॳճͷಡΈࠐΈΑΓͦͷޙͷମݧΛॏࢹ
Ұൠతʹ41"Λ࠾༻Ͱ͖Δ͔ w 41"ʹ͢ΔϢʔβʔϝϦοτͱ։ൃͷఱṝ w ఆ͞ΕΔར༻ύλʔϯ͕41"ʹϚον͢Δ͔ w ηογϣϯɺ17ηογϣϯ͕ଟ͚Ε૬ੑ͕͍͍ w ݕࡧ4/4͔ΒͷϏδλʔ͕ଟ͚ΕॳճͷಡΈࠐΈΛૣ͘͢Δ w
αϙʔτରͷϒϥβ w 4&0ͷॏཁੑ
࠷ޙ༐ؾ w ͍ͥͬͨʹࣗͰͳΜͱ͔͢Δܾҙ
3FBDUͱ3FEVYʹΑΔ εςʔτϑϧΞϓϦέʔγϣϯ
εςʔτϑϧΞϓϦέʔγϣϯ w )551ϦΫΤετʹରͯ͠)551ϨεϙϯεΛฦ͢ ˠεςʔτϨε w σʔλϕʔεͰӬଓԽ w ηογϣϯʹΑͬͯ࿈ଓੑΛอͭ w 41"(6*ΞϓϦέʔγϣϯ
ˠεςʔτϑϧ
Component Props Component Component Component Component Component Virtual DOM Virtual
DOM Virtual DOM Props Props 3FBDU w ΞϓϦέʔγϣϯ $PNQPOFOUͷू߹ମ w $PNQPOFOUೖྗΛݩʹ ৽ͨͳ$PNQPOFOUΛग़ྗ͢Δ ؔͱΈͳͤΔ w ࠷ऴతʹ%0.$PNQPOFOUΛ ग़ྗ͢Δ
σʔλϑϩʔ w 1SPQT ˠ֎෦͔Βͷೖྗ w 4UBUFT ˠ$PNQPOFOUͷঢ়ଶ w $POUFYU ˠࢠଙ$PNQPOFOUʹΘΔঢ়ଶ
࣌ࠁ import * as React from 'react'; interface TimeProps {
time: Date, } export const Time: React.SFC<TimeProps> = ({time}) => { return <time dateTime={time.toISOString()}>{time.toLocaleString()}</time>; };
ͭͷ$PNQPOFOU w 4UBUFMFTT'VODUJPOBM$PNQPOFOU w 1VSF$PNQPOFOU w $PNQPOFOU
4UBUFMFTT'VODUJPOBM$PNQPOFOU w ؔ w ঢ়ଶΛ࣋ͨͳ͍ Component Props Component Component Props
1VSF$PNQPOFOU w Ϋϥε w ঢ়ଶΛ࣋ͭ w 4UBUFTJNNVUBCMFͳΦϒδΣΫτ Component Props Component
Component Props States
$PNQPOFOU w Ϋϥε w ঢ়ଶΛ࣋ͭ w 4UBUFTJNNVUBCMFͱݶΒͳ͍ Component Props Component
Component Props States
ͭͷ$PNQPOFOU w 4UBUFMFTT'VODUJPOBM$PNQPOFOU͕࠷୯७ w 1VSF$PNQPOFOUΛ͏͜ͱ͕ଟ͍
*NNVUBCMF w σʔλ͕JNNVUBCMFͰ͋Δํ͕߹͕͍͍ w ݹ͍ͱ৽͍͕͠ಉ͡ͳΒԿ͠ͳ͍͍ͯ͘ w *NNVUBCMFͳΦϒδΣΫτ===ͰൺֱͰ͖Δ
*NNVUBCMF w 0CKFDUBTTJHO const newObj = Object.assign({}, oldObj, { key:
value }) w 4QSFBE0QFSBUPS const newObj = { ...oldObj, key: value } w *NNVUBCMFKT
Store Reducer State Action dispatch subscribe 3FEVY w ୯Ұͷ4UPSFʹશͯͷঢ়ଶ w
TVCTDSJCFͰมԽΛݕͰ͖Δ w 0CTFSWFSύλʔϯ w ঢ়ଶΛม͍͑ͨͱ͖ 4UPSFʹ"DUJPOΛૹΔ w 3FEVDFS͕"DUJPOʹԠͯ͡ ঢ়ଶΛมߋ͢Δ
"DUJPOϝιουσΟεύον w "DUJPOϝιουͱύϥϝʔλΛ߹Θͤͨͷ w "DUJPO$SFBUPSͱݺΕΔϑΝΫτϦʔؔͰ࡞Δ w 3FEVDFS4UPSFΛมߋ͢ΔͨΊͷϨγʔό w DPNCJOF3FEVDFSTͰෳͷ3FEVDFSΛΈ߹Θͤͯ 4UPSFΛׂ౷࣏͢Δ
3FBDU3FEVY Component Component Component Component Virtual DOM Virtual DOM Virtual
DOM Props Props Component Component
3FBDU3FEVY Connected Provider Connected Component Component Component Component Virtual DOM
Virtual DOM Virtual DOM Props Props Component Component
3FBDU3FEVY w 1SPWJEFS͕DPOUFYUͰ4UPSFΛࢠଙ$PNQPOFOUʹఏڙ w DPOOFDUؔͰ$PNQPOFOUΛ4UPSFͱଓ w 4UPSFΛTVCTDSJCFͯ͠1SPQTʹม͢Δ w ΠϕϯτΛ"DUJPOͱͯ͠4UPSFʹ͑Δ w
ˠ%*
࣌ࠁ import * as React from 'react'; interface TimeProps {
time: Date, } export const Time: React.SFC<TimeProps> = ({time}) => { return <time dateTime={time.toISOString()}>{time.toLocaleString()}</time>; };
࣌ࠁ import * as React from 'react'; import {connect} from
'react-redux'; interface TimeProps { time: Date, } const Time: React.SFC<TimeProps> = ({time}) => { return <time dateTime={time.toISOString()}>{time.toLocaleString()}</time>; }; export default connect(state => ({ time: state.time }))(Time);
3FEVY w ΞϓϦέʔγϣϯશମͷঢ়ଶ w 0CTFSWFSύλʔϯͱ%* w 4UPSFͷઃܭ͕ॏཁ w 3FEVDFSͷΈ߹ΘͤͰׂ౷࣏ w
Կ͔3FEVYͷ4UPSFʹೖΕΔඞཁͳ͍
8FC"1*ͷϨεϙϯε w 3FEVYͷ4UPSFʹͲ͏อ࣋͢Δͷ͔ w ϦιʔεͷεςʔτϚγϯ w ະऔಘɾ௨৴தɾऔಘࡁΈɾऔಘࣦഊ w RemoteResource<T, E>
3FNPUF3FTPVSDF5 & empty pending resolved<T> failed<E> request succeeded failed reload
reload
3FNPUF3FTPVSDF5 & w latestValueͱͯ͠࠷ޙͷΛอ͓࣋ͯ͘͠ w Ϧϩʔυதʹ͕ফ͑ͳ͍ w औಘʹޭͨ࣌͠ࠁอ͓࣋ͯ͘͠ͱศར w ߴ֊ؔ
RemoteResource<T, E>.map<U>((T) -> U) -> RemoteResource<U, E>
3FNPUF3FTPVSDF5 & enum State { EMPTY = "empty", PENDING =
"pending", RESOLVED = "resolved", FAILED = "failed", } abstract class RemoteResource<T, E> { abstract state: State; abstract latestValue: T | null; abstract error: E | null; }
3FNPUF3FTPVSDF5 & w ݱࡏͷঢ়ଶʹΑΒͣ࣍ͷঢ়ଶΛද͢Έ࡞Δ RemoteResource<T, E>.apply(Next<T, E>) -> RemoteResource<T, E>
w "DUJPOʹNext<T, E>͚ͩ࣋ͨͤΔ w 3FEVDFS͕apply͢Δ
3FEVY4BHB
3FEVY w 3FEVYঢ়ଶͷཧʹಛԽ͍ͯ͠Δ w ࡞༻ w ݱ࣮ͷΞϓϦέʔγϣϯ෭࡞༻Λ࣋ͭ
3FEVY4BHB w 3FEVYNJEEMFXBSF w ෭࡞༻ඇಉظੑΛղܾ͢Δ w (FOFSBUPSGVODUJPO
࣌ࠁ const updateTime = createAction('UPDATE_TIME', (time: Date) => ({ time:
time })); const timeReducer = handleAction(updateTime, (state, action) => action.payload!.time, new Date() ); function * ticktack() { while (true) { yield put(updateTime(new Date())); yield delay(1000); } } function * rootSaga() { yield all([ fork(ticktack), ]); }
࣌ࠁ const sagaMiddleware = createSagaMiddleware(); const store = createStore( combineReducers({
time: timeReducer, }), applyMiddleware(sagaMiddleware) ); sagaMiddleware.run(rootSaga);
࣌ࠁ import * as React from 'react'; import {connect} from
'react-redux'; interface TimeProps { time: Date, } const Time: React.SFC<TimeProps> = ({time}) => { return <time dateTime={time.toISOString()}>{time.toLocaleString()}</time>; }; export default connect(state => ({ time: state.time }))(Time);
3FEVY4BHB w 8FC"1*ͷΞΫηε w takeF⒎FDUͰGetSomeRequested"DUJPOΛͭ w ϦΫΤετ͢Δ w putF⒎FDUͰSomeRecieved"DUJPOΛ͛Δ
8FCϖʔδͱͯ͠ͷ41"
8FCϖʔδͱͯ͠ͷ41" w 41"8FCϒϥβͰಈ࡞͢Δ w 8FCϒϥβʹ8FCಛ༗ͷࣄ͕͋Δ w 63- w )JTUPSZ
63- w 3FBDU3PVUFSW w શͯͷϖʔδʹ63-ΛׂΓৼΔ w MPDBUJPOͷมԽʹԠͯ͡$PNQPOFOUΛΓସ͑Δ w ։ൃதʹϦϩʔυͰ͖ͯศར w
(PPHMF"OBMZUJDTͳͲͱ૬ੑ͕Α͍
)JTUPSZ w ϒϥβͷʮΔʯલͷॴʹΔ w φϏήʔγϣϯͷʮΔʯϘλϯ w ҙຯ্ͷ্Ґ֊ʹͬͯ΄͍͠ w ͦ͜Ͱ͞ΒʹϒϥβͷʮΔʯΛԡͨ͠Βʁ Δ
)JTUPSZ w ʮΔʯઌ͕લͷϖʔδͳΒ window.history.back() w ʮΔʯઌ͕લͷϖʔδͰͳ͚Ε window.history.replaceState() A1 A2 A3
B1 B2 C1 C2 A1 A2 B2
)JTUPSZ w MPDBUJPOʹIJTUPSZTUBUFؚΊΔ w QVTI4UBUFͰIJTUPSZTUBUFʹલ ͷMPDBUJPOΛอଘ͢Δ w IJTUPSZTUBUFʮΔʯʮਐΉʯ Ͱ෮ݩ͞ΕΔ w
ৗʹલͷϖʔδ͕ಘΒΕΔ export interface Location { pathname: Pathname; search: Search; state: LocationState; hash: Hash; key: LocationKey; } window.history.pushState({ lastLocation: location, }, "A2", "/a/2");
·ͱΊ
w 41"(6*ΞϓϦέʔγϣϯ w ঢ়ଶͷཧ͕ॏཁ w 3FBDU 3FEVYͳͲΛ͏·͘͏ w ߴͳϢʔβʔΠϯλʔϑΣʔεΛ࣮ݱͰ͖Δ