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
イカリング2におけるシングルページアプリケーション
Search
cockscomb
October 02, 2017
Programming
7.7k
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.4k
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
AIと壁打ちしながら進めるコスト管理
fufuhu
2
1.9k
Flow は今どうなっているか
mizdra
PRO
0
880
Kiroで創り、AgentCoreで繋ぐ!AWSで実践する「AI-DLC」から「AIエージェント統合」までの最新地図
licux
2
260
DynamoDBの基礎を振り返りながらベクトル検索機能を理解する
musan
3
260
{ Android | Kotlin } Gradle Plugin in 2026
ryunen344
1
270
PyO3 で既存 Python 評価器を Rust core 化する ー wasm-bindgen でブラウザにも配るための設計
kdash
1
350
Gmail/Google DriveをトリガーにAIエージェントを動かそう! / Run AI agents with Gmail/Google Drive as triggers!
har1101
3
460
高専キャリア LT 発表内容
crysta1221
6
5.5k
承認済みなのに差戻しできてしまうバグ、型で潰せます
shinchit
0
130
ソフトウェアラスタライザ
fadis
1
780
FDEとは、何者なのか?
masapyon1212
0
130
AWS Step Functions 大規模並列の壁を越える / jaws-sonic-2026-niigata-step-functions
kasacchiful
PRO
0
300
Featured
See All Featured
Designing Dashboards & Data Visualisations in Web Apps
destraynor
232
55k
The #1 spot is gone: here's how to win anyway
tamaranovitovic
3
1.1k
Become a Pro
speakerdeck
PRO
31
6.2k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
287
14k
Crafting Experiences
bethany
1
280
Code Reviewing Like a Champion
maltzj
528
40k
Introduction to Domain-Driven Design and Collaborative software design
baasie
1
970
Raft: Consensus for Rubyists
vanstee
141
7.7k
Agile Actions for Facilitating Distributed Teams - ADO2019
mkilby
0
270
Bridging the Design Gap: How Collaborative Modelling removes blockers to flow between stakeholders and teams @FastFlow conf
baasie
0
690
How Fast Is Fast Enough? [PerfNow 2025]
tammyeverts
3
860
Why Our Code Smells
bkeepers
PRO
340
58k
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 ߴͳϢʔβʔΠϯλʔϑΣʔεΛ࣮ݱͰ͖Δ