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
redux-pluto
Search
Yosuke Furukawa
PRO
April 19, 2018
Programming
18
4.4k
redux-pluto
Folio Scramble! #1 で話した redux best practiceの話です。
Yosuke Furukawa
PRO
April 19, 2018
Tweet
Share
More Decks by Yosuke Furukawa
See All by Yosuke Furukawa
Node.js, Deno, Bun 最新動向とその所感について
yosuke_furukawa
PRO
9
3.8k
Welcome JSConf.jp 2024
yosuke_furukawa
PRO
1
4.1k
tc39 x jsconf.jp Panel Discussion 2024
yosuke_furukawa
PRO
0
230
Removing Corepack
yosuke_furukawa
PRO
9
1.6k
JavaScript Runtime とはなにか
yosuke_furukawa
PRO
15
2.8k
Strip Types と Storage
yosuke_furukawa
PRO
4
410
Module Harmony について
yosuke_furukawa
PRO
3
1.7k
LTのやり方
yosuke_furukawa
PRO
16
2.6k
AppRouter Panel Talk
yosuke_furukawa
PRO
3
810
Other Decks in Programming
See All in Programming
5つのアンチパターンから学ぶLT設計
narihara
1
160
Rubyでやりたい駆動開発 / Ruby driven development
chobishiba
1
650
Node-RED を(HTTP で)つなげる MCP サーバーを作ってみた
highu
0
120
「テストは愚直&&網羅的に書くほどよい」という誤解 / Test Smarter, Not Harder
munetoshi
0
110
0626 Findy Product Manager LT Night_高田スライド_speaker deck用
mana_takada
0
160
LT 2025-06-30: プロダクトエンジニアの役割
yamamotok
0
720
WebViewの現在地 - SwiftUI時代のWebKit - / The Current State Of WebView
marcy731
0
110
Quand Symfony, ApiPlatform, OpenAI et LangChain s'allient pour exploiter vos PDF : de la théorie à la production…
ahmedbhs123
0
140
Azure AI Foundryではじめてのマルチエージェントワークフロー
seosoft
0
160
ruby.wasmで多人数リアルタイム通信ゲームを作ろう
lnit
3
450
コードの90%をAIが書く世界で何が待っているのか / What awaits us in a world where 90% of the code is written by AI
rkaga
50
33k
ISUCON研修おかわり会 講義スライド
arfes0e2b3c
1
420
Featured
See All Featured
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
53
2.9k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
35
2.4k
Building a Scalable Design System with Sketch
lauravandoore
462
33k
Statistics for Hackers
jakevdp
799
220k
Imperfection Machines: The Place of Print at Facebook
scottboms
267
13k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
8
810
How STYLIGHT went responsive
nonsquared
100
5.6k
Optimizing for Happiness
mojombo
379
70k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
248
1.3M
Rebuilding a faster, lazier Slack
samanthasiow
82
9.1k
The Art of Programming - Codeland 2020
erikaheidi
54
13k
Become a Pro
speakerdeck
PRO
28
5.4k
Transcript
redux-pluto 2018/04/19 @ Folio Meetup # Scramble! #1
Twitter: @yosuke_furukawa Github: yosuke-furukawa
redux-pluto • ϦΫϧʔτςΫϊϩδʔζࣾͰ։ൃதͷϘΠϥʔϓ Ϩʔτ • େن։ൃ͚ɺϕετϓϥΫςΟεΛूΊͨ ͷ • ͪͳΈʹ·ͩ։ൃதͳͷͰࠓϦϙδτϦެ ։Ͱ͖ͳ͍Ͱ͢ɺӶҙקΊதͰ͢ɻ
͍͢·ͤΜɺɺɺ
redux-pluto • ϦΫϧʔτςΫϊϩδʔζࣾͰ։ൃதͷϘΠϥʔϓ Ϩʔτ • େن։ൃ͚ɺϕετϓϥΫςΟεΛूΊͨ ͷ • ͪͳΈʹ·ͩ։ൃதͳͷͰࠓϦϙδτϦެ ։Ͱ͖ͳ͍Ͱ͢ɺӶҙקΊதͰ͢ɻ
͍͢·ͤΜɺɺɺ ࠓ͜ͷϕετϓϥΫςΟεΛ νϥݟͤ
ϕετϓϥΫςΟε ΞʔΩςΫνϟฤ
ϕετϓϥΫςΟε 1 ඇಉظσʔλϩʔυ
ඇಉظσʔλϩʔυ • redux-async-loader • SSRͰCSRͰಈ͘σʔλFetchؔΛఏڙ ͯ͘͠ΕΔ • σʔλFetchதReactͷrenderΛ͠ͳ͍࡞Γ
ඇಉظσʔλϩʔυ • redux-async-loader import { compose } from 'recompose'; export
default compose( // CSR Ͱ SSR Ͱ྆ํಈ͘ // σʔλ͕ϩʔυ͞ΕͯΔͱloading state͕trueʹͳΓɺͦͷظؒ // component͕render͞Εͳ͍ɻ asyncLoader((props, { dispatch }) => dispatch(loadUsers(props))), connect({ ... }, { ... }) )(class UserList exptends React.Component { // ... });
ඇಉظσʔλϩʔυ • ଞͷOSSࣄྫ • CyberAgent: https://github.com/kouhin/redux- dataloader • Next.js: getInitialProps
https://github.com/zeit/ next.js/blob/master/examples/with-redux/pages/ index.js#L8-L13 • Nuxt.js: asyncData
ඇಉظσʔλϩʔυ • Ͳͷํ๏Ͱ͍͍ͩͨಉ͕ͩ͡ɺredux-async- loaderͲ͜ͷίϯϙʔωϯτ͔ΒͰඇಉظ σʔλϩʔυͰ͖Δɻ • Next.js, Nuxt.js ͷͷRootͰͷΈൃՐՄೳ •
େن։ൃͩͱ్தͷComponent͔ΒͰඇಉ ظϩʔυͰ͖Δํ͕خ͍͜͠ͱɻ
ϕετϓϥΫςΟε 2 reduxϑϩʔ੍ޚ
reduxϑϩʔ੍ޚ • redux-effects-steps https://github.com/recruit-tech/redux-effects-steps • redux-thunksagaɺObservableͱ͍͏खஈ͕͋Δ ͕ͦΕΒͬͯͳ͍ɻ • ϑϩʔ੍ޚͰෳࡶͳॲཧΛॻ͚ΔΑ͏ʹͨ͘͠ͳ͍ •
ෳࡶʹͳͬͯ͠·͏ͷͰ͋Εmiddlewareʹಀ͕͢
reduxϑϩʔ੍ޚ • redux-effects-steps https://github.com/recruit-tech/redux-effects-steps • import { createAction } from
'redux-actions'; import { steps } from 'redux-effects-steps'; import { fetchrRead } from 'redux-effects-fetchr'; const fetchUserRequest = createAction('FETCH_USER_REQUEST'); const fetchUserSuccess = createAction('FETCH_USER_SUCCESS'); const fetchUserFail = createAction('FETCH_USER_FAIL'); function fetchUser({ user }) { return steps( // ϦΫΤετͨ͠ΒϦΫΤετͨ͜͠ͱΛActionͰൃՐ͓ͤͯ͘͞ɻ fetchUserRequest(), // ຊϦΫΤετ fetch ॲཧ fetchrRead('users', { user }), // ޭͨ͠ΒSuccess Action, ࣦഊͨ͠Β Failure Action [fetchUserSuccess, fetchUserFail] ); }
reduxϑϩʔ੍ޚ • ଞͷOSSࣄྫ • redux-thunk • redux-saga • redux-observable
reduxϑϩʔ੍ޚ • redux-thunkԿͰͰ͖͗͢ΔɺActionΛॻ͘ॴͰࡉ͔͍ॲ ཧ͕ॻ͚ΔͷΓա͗ײ͋Δɻ͕ͦ͜Ԛ͘ͳΓͦ͏ɻ • redux-sagasagaͱ͍͏ϨΠϠͰόοΫάϥϯυϓϩηε తʹԿͰΔɻ͜͜·Ͱͷॲཧ͕ඞཁʹͳͬͨέʔε͕গͳ ͍ɺΑ͋͘ΔͷϦΫΤετΛൃՐͯͦ͠Ε͕ޭ͔ࣦͨ͠ഊ ͔ͨ͠ఔɺͦΕ͚ͩͰsagaΦʔόʔΩϧײ •
observableRxJSͰྲྀΕΛ੍ޚ͢Δͱ͍͏ͷ͕ͩɺͦ͜· Ͱͷྲྀྔ੍ݶ͕ඞཁʹͳͬͨ͜ͱ͕ͳ͍
ϕετϓϥΫςΟε 3 ducks
ducks • https://github.com/erikras/ducks-modular- redux • reducer, actions, action creatorͱ͍͏ػೳͰ ͚ΔͷͰͳ͘ɺUserɺArticleͱ͍ͬͨΑ
͏ͳϦιʔεͷѻ͍Ͱ̍ͭͷϑΝΠϧʹ͢Δ
ducks • https://github.com/erikras/ducks-modular- redux /* @flow */ /** * Initial
State */ const SALON = "redux-proto/salon"; export const [ FIND_SALON_BY_ID_REQUEST, FIND_SALON_BY_ID_SUCCESS, FIND_SALON_BY_ID_FAIL ] = createAsyncActionTypes(`${SALON}/find_id`); /** * Action creators */ const findSalonByIdRequest = createAction(FIND_SALON_BY_ID_REQUEST); const findSalonByIdSuccess = createAction(FIND_SALON_BY_ID_SUCCESS); const findSalonByIdFail = createAction(FIND_SALON_BY_ID_FAIL);
ducks • https://github.com/erikras/ducks-modular- redux /* @flow */ /** * Reducer
*/ export default (handleActions( { [FIND_SALON_BY_ID_REQUEST]: state => ({ … }), } )) /** * Selector */ export default (createSelector((state) => {…}, (items) => {…}))
ducks • actions, action creator, reducer ͚ͩͰͳ͘ɺselector· Ͱதʹ࣋ͭɻ • ϑΝΠϧ͕େ͖͘ͳΓͦ͏ͳ࣌ϑΥϧμʹͯ͠ϑΝΠϧ
ׂ͢Δͷ༗Γɻ͜ͷล͖ʹ • re-ducksͱ͍͏ͷ͋Δ͕ɺ͜ΕͱͷϋΠϒϦουײɻ • ཁΓ͍ͨͷϦιʔε࣠Ͱ·ͱΊΔํ͕ػೳ࣠Ͱ·ͱ ΊΔΑΓॻ͖͘͢ɺݟ͔ͬͨ͢ɻ
ϕετϓϥΫςΟε 4 APIఆٛ
APIఆٛ • agreed https://github.com/recruit-tech/ agreed • Consumer Driven ContractΛ࣮ફ •
ϑϩϯτΤϯυ͕த৺ʹͳͬͯ։ൃΛ͢͢Ί ΔΈʹͳ͍ͬͯΔɻ
APIఆٛ • agreedͰAPIͷmockΛઌʹ࡞ • mockΛ࡞ΓऴΘͬͨΒAPI࡞ऀ(Server Side)ʹagreed-uiͰཁٻΛڞ༗ɻ • API͕ߏஙͰ͖͖ͯͨΒagreed-clientͰςετ έʔεͱ࣮ͯ͠ߦ͞ΕΔɻ
APIఆٛ
APIఆٛ • ଞOSSࣄྫ • Swagger • Pact
APIఆٛ • SwaggerAPIͷ༷ఆٛͰ͋ͬͯAPIͷཁٻ Ͱͳ͍ɻ͋͘·ͰυΩϡϝϯτɺmock࡞ ΕΔ͕࡞Γ͘͢ͳͦ͞͏ɻ • Pactclientͷςετσʔλ͔Βserverͷ νΣοΫΛ͢ΔͨΊͷσʔλΛࣗಈੜ͢Δ Έɻςετσʔλ͕ඞཁͳͷਏ͍ɻɻ
ϕετϓϥΫςΟε UIฤ
ϕετϓϥΫςΟε ϑΥʔϜ
ϑΥʔϜฤ • 2017ͷformʹ͍ͭͯ • https://speakerdeck.com/yosuke_furukawa/ 2017nian-falseformfalsehua
ࠓͷ form ͷΛཧ͢Δॴ %0. 3FBDU 3FEVY +BWB4DSJQUͷϝϞϦ
ࠓͷ form ͷΛཧ͢Δॴ %0. 3FBDU 3FEVY +BWB4DSJQUͷϝϞϦ 6ODPOUSPMMFE 'PSN $POUSPMMFE
'PSN
Uncontrolled vs Controlled • DOMͷΛ͏ (Uncontrolled) • DOM͔Βऔ͖ͬͯͨΛJSͷϝϞϦʹೖΕ ͯɺεφοϓγϣοτͱͯ͠͏ (Controlled)
Uncontrolled form // React ͩͱ͜͏ class NameForm extends React.Component {
// … handleSubmit(event) { alert('A name was submitted: ' + this.input.value); event.preventDefault(); } render() { return ( <form onSubmit={this.handleSubmit}> <label> Name: <input type="text" ref={(input) => this.input = input} /> </label> <input type="submit" value="Submit" /> </form> ); } }
Controlled form class NameForm extends React.Component { // … handleChange(event)
{ this.setState({value: event.target.value}); } handleSubmit(event) { alert('A name was submitted: ' + this.state.value); event.preventDefault(); } render() { return ( <form onSubmit={this.handleSubmit}> <label> Name: <input type="text" value={this.state.value} onChange={this.handleCha </label> <input type="submit" value="Submit" /> </form> ); } }
Uncontrolled vs Controlled • Controlled ͳํ ͜͜Ͱ React ͷ state
ͱ ͯ͠ཧ͢Δ • Uncontrolled ͳํDOMʹ͚ͩཧͤ͞Δ
Uncontrolled vs Controlled • Facebook ͕ਪͯ͠Δͷ Controlled Ұ • React
ͷ v-dom ߋ৽ͷλΠϛϯάͱ߹Θͤͯ React ͕࠷దԽͨ͠ํ๏ͰDOMʹөͤ͞Δ͜ͱ ͕Ͱ͖Δ • ͪΐͬͱڽͬͨformΛ࡞ΕେମControlledͰ࣮ ͢Δඞཁ͕ग़ͯ͘Δɻ
Uncontrolled vs Controlled • jQuery UI Έ͍ͨͳϥΠϒϥϦେମ Uncontrolled ͳํ๏ͰͬͯΔ͜ͱ͕ଟ͍ʢؾ ͕͢Δʣ
• طଘͷࢿ࢈͕jQueryʹ͋ͬͯͦΕ͕ Uncontrolled ͳํ๏Ͱ࣮ݱ͞ΕͯΔͳΒ͏ͷ ྑ͍͕ɺجຊ Controlled Ͱྑ͍ؾ͕͢Δɻɹ
Uncontrolled vs Controlled • https://goshakkk.name/controlled-vs-uncontrolled-inputs-react/
ࠓͷ form ͷΛཧ͢Δॴ %0. 3FBDU 3FEVY +BWB4DSJQUͷϝϞϦ 6ODPOUSPMMFE 'PSN ͏Εͯྑ͍͔
$POUSPMMFE 'PSN ͓ͬͪ͜͢͢Ί
Ͱ 2017 ݱࡏ state ͕ ෳ͋Δ
ࠓͷ form ͷΛཧ͢Δॴ %0. 3FBDU 3FEVY -PDBMTUPSBHF DPPLJF *OEFYFE%#
Ͳ͜ʹΛอଘ͢Δͷ͕ਖ਼͠ ͍ͷ͔ʁ
None
6TF3FBDUGPSFQIFNFSBMTUBUFUIBUEPFTO`UNBUUFSUPUIF BQQHMPCBMMZ
ࠓͷ form ͷΛཧ͢Δॴ %0. 3FBDU 3FEVY -PDBMTUPSBHF DPPLJF *OEFYFE%# &QIFNFSBM
&UFSOBM 'PSFWFS
ࠓͷ form ͷΛཧ͢Δॴ %0. 3FBDU 3FEVY -PDBMTUPSBHF DPPLJF *OEFYFE%# Ұ࣌తͳGPSNͷ
ͳΒ͜͜ʹ HMPCBMͳTUBUFͳΒ ͜͜ʹ
ͰͬͯΈΔͱ
React ͷ state ͱ Redux ͷ state Ͱ form ͔ͩΒͱ͍ͬͯ
͚Δͷ໘
ࠓ
ࠓͷ form ͷΛཧ͢Δॴ %0. 3FBDU 3FEVY -PDBMTUPSBHF DPPLJF *OEFYFE%# ͳΜ͔ύϑΥʔϚϯεͷϘ
τϧωοΫ͕͋ͬͨΒ͜͜ جຊ͜͜
twitter Lite ͷߏ
ࠓͷ form ͷΛཧ͢Δॴ %0. 3FBDU 3FEVY -PDBMTUPSBHF DPPLJF *OEFYFE%# UXJUUFSͷGPSNͷใ
Ұ୴͜͜ͰCV⒎FS จࣈهड़ͨ͠Β SFEVDFSʹߦ͘
͋Δఔ form ͷใ React ͰͨΊͯɺจࣈೖΕ ͨΒ Redux ʹ flush ͤ͞Δɻ
ϕετϓϥΫςΟε ԾεΫϩʔϧ
ԾεΫϩʔϧ • େલఏ: • DOMͷཁૉ͕૿͑Ε૿͑Δ΄Ͳϖʔδ ॏ͘ͳΔ͠ɺΧΫͭ͘ • ϒϥβ্ͷϝϞϦ͕େ͖͘ͳΔ • ݟ͑ͯͳ͍ॴDOMʹදࣔ͠ͳ͍͍ͯ͘
ԾεΫϩʔϧ • ݟ͑ͯΔͱ͜Ζ͚ͩDOMͱͯ͠දࣔ͢Δ • react-virtualized Λ͏ %0.ͱͯ͠ දࣔ %0.͔Β ഁغ
ϕετϓϥΫςΟε ແݶεΫϩʔϧ
ແݶεΫϩʔϧ • େલఏ: • Ϣʔβʔͷճ༡࣌ؒΛ૿͍ͨ͠ɻ ݕࡧͨ͠Β2ϖʔδҎ߱ͪΌΜͱݟ͍ͤͨɻ • ͪ·ͪ·࣍ͱ͔ϖʔδͷϦϯΫΛԡ͞ͳ͖Ό͍͚ͳ͍ͷ໘ ʢಛʹϞόΠϧʣ •
͔ͱݴͬͯSEOઈରʢεΫϩʔϧ͢ΔͷϢʔβʔ͚ͩͰ Google CrawlerεΫϩʔϧΠϕϯτ·ͰൃՐͯ͘͠Εͳ͍ʣ
ແݶεΫϩʔϧ • ແݶεΫϩʔϧ x ϖʔδωʔγϣϯ • ϢʔβʔΫϩʔϥʔ ྆ํϑϨϯυϦʔʹɻ Δ 1
2 3 4 5 6 7 8 9 10 ࣍
όουϊϋ ͬͯΈ͚ͨͲμϝͩͬͨฤ
ϋϚΓ·ͬͨ͘ babel plugins
babel-plugin-transform-react- inline-elementsͰIEͷࢮ
transform-react-constant- elementsͰbabelόάΛ౿Ή
transform-react-constant- elementsͰbabelόάΛ౿Ή • ൵C
Α͘Α͘ߟ͑Δͱͨ͘͞Μ͋Δ • fetchrͷෆ۩߹Λ౿Μͩ ʢओʹηΩϡϦςΟ໘ʣ • React v15ͰϝϞϦʔϦʔΫʹ·͞ΕΔɺv16Ͱղফ • react-router v4ະରԠ
• etc…
Α͘Α͘ߟ͑Δͱͨ͘͞Μ͋Δ • fetchrͷෆ۩߹Λ౿Μͩ ʢओʹηΩϡϦςΟ໘ʣ • React v15ͰϝϞϦʔϦʔΫʹ·͞ΕΔɺv16Ͱղফ • react-router v4ະରԠ
• etc… ܾͯ͠ॱ෩Ͱͳ͍͕ɺԶΒͬ ͍ͯͧ͘ʂʂʂʂ
·ͱΊ • ϕετϓϥΫςΟεʢΞʔΩςΫνϟฤʣ • ඇಉظϩʔυ • reduxϑϩʔ੍ޚ • ducks •
APIఆٛ • ϕετϓϥΫςΟε(UIฤ) • ϑΥʔϜ • ԾεΫϩʔϧ • ແݶεΫϩʔϧ • όουϓϥΫςΟε • babel plugin…, onlyUpdateForPropTypes…, etc