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
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
Yosuke Furukawa
PRO
April 19, 2018
Programming
18
4.5k
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
デザインシステムが必須の時代に
yosuke_furukawa
PRO
2
200
Node.js, Deno, Bun 最新動向とその所感について
yosuke_furukawa
PRO
10
4.9k
Welcome JSConf.jp 2024
yosuke_furukawa
PRO
1
4.5k
tc39 x jsconf.jp Panel Discussion 2024
yosuke_furukawa
PRO
0
300
Removing Corepack
yosuke_furukawa
PRO
9
1.8k
JavaScript Runtime とはなにか
yosuke_furukawa
PRO
15
3k
Strip Types と Storage
yosuke_furukawa
PRO
4
470
Module Harmony について
yosuke_furukawa
PRO
4
1.8k
LTのやり方
yosuke_furukawa
PRO
16
2.9k
Other Decks in Programming
See All in Programming
Data-Centric Kaggle
isax1015
2
790
CSC307 Lecture 08
javiergs
PRO
0
670
20260127_試行錯誤の結晶を1冊に。著者が解説 先輩データサイエンティストからの指南書 / author's_commentary_ds_instructions_guide
nash_efp
1
1k
CSC307 Lecture 07
javiergs
PRO
1
560
副作用をどこに置くか問題:オブジェクト指向で整理する設計判断ツリー
koxya
1
620
15年続くIoTサービスのSREエンジニアが挑む分散トレーシング導入
melonps
2
230
AIフル活用時代だからこそ学んでおきたい働き方の心得
shinoyu
0
140
360° Signals in Angular: Signal Forms with SignalStore & Resources @ngLondon 01/2026
manfredsteyer
PRO
0
140
Automatic Grammar Agreementと Markdown Extended Attributes について
kishikawakatsumi
0
200
React 19でつくる「気持ちいいUI」- 楽観的UIのすすめ
himorishige
11
7.5k
疑似コードによるプロンプト記述、どのくらい正確に実行される?
kokuyouwind
0
390
AI によるインシデント初動調査の自動化を行う AI インシデントコマンダーを作った話
azukiazusa1
1
760
Featured
See All Featured
Building the Perfect Custom Keyboard
takai
2
690
<Decoding/> the Language of Devs - We Love SEO 2024
nikkihalliwell
1
140
sira's awesome portfolio website redesign presentation
elsirapls
0
160
Rails Girls Zürich Keynote
gr2m
96
14k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
659
61k
Faster Mobile Websites
deanohume
310
31k
The Art of Programming - Codeland 2020
erikaheidi
57
14k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
31
3.1k
Java REST API Framework Comparison - PWX 2021
mraible
34
9.2k
Marketing to machines
jonoalderson
1
4.7k
The SEO Collaboration Effect
kristinabergwall1
0
360
What the history of the web can teach us about the future of AI
inesmontani
PRO
1
440
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