Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Speaker Deck
PRO
Sign in
Sign up for free
イカリング2におけるシングルページアプリケーション
cockscomb
October 02, 2017
Programming
2
6.7k
イカリング2におけるシングルページアプリケーション
cockscomb
October 02, 2017
Tweet
Share
More Decks by cockscomb
See All by cockscomb
GraphQL放談
cockscomb
4
1.2k
GraphQL Highway
cockscomb
24
5.5k
吉田を支える技術
cockscomb
0
800
コーポレートサイトを静的化してAmplify Consoleにデプロイする
cockscomb
0
2.9k
ユーザインターフェイスと非同期処理
cockscomb
5
1.3k
GUIアプリケーションの構造と設計
cockscomb
10
9.3k
あなたの知らない UIKit の世界 — UITableView に UITextView を置きたい
cockscomb
1
6.5k
iOSアプリエンジニアのためのAndroidアプリ開発
cockscomb
7
1.5k
Swift 2 Error Handling in Practice
cockscomb
5
6.7k
Other Decks in Programming
See All in Programming
C言語でメモリ管理を考えた話
hkawai
0
190
byte列のbit表現を得るencodingライブラリ作った
convto
1
100
読みやすいコードを書こう
yutorin
0
400
heyにおけるSREの大切さ~マルチプロダクト運用の「楽しさ」と「難しさ」および今後の展望~
fufuhu
3
1.6k
Becoming an Android Librarian
skydoves
3
460
Licences open source : entre guerre de clochers et radicalité
pylapp
1
260
iOSアプリの技術選択2022
tattn
6
2.4k
Monadic Java
mariofusco
4
260
Language Summit 2022: WebAssembly: Python in the browser and beyond
tiran
2
310
アプリのログをチーム外で活用してもらうためにやったこと
shotakashihara
0
190
Android Architecture Design With Koin
agiuliani
0
230
Swift Concurrencyによる安全で快適な非同期処理
tattn
2
310
Featured
See All Featured
No one is an island. Learnings from fostering a developers community.
thoeni
9
1.1k
How to name files
jennybc
39
58k
Practical Orchestrator
shlominoach
178
8.6k
Atom: Resistance is Futile
akmur
255
20k
Put a Button on it: Removing Barriers to Going Fast.
kastner
56
2.3k
Making Projects Easy
brettharned
98
4.3k
Web development in the modern age
philhawksworth
197
9.3k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
315
19k
Learning to Love Humans: Emotional Interface Design
aarron
261
37k
Music & Morning Musume
bryan
35
4.1k
Six Lessons from altMBA
skipperchong
14
1.3k
Building a Scalable Design System with Sketch
lauravandoore
447
30k
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 ߴͳϢʔβʔΠϯλʔϑΣʔεΛ࣮ݱͰ͖Δ