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
React Nativeで作ったアプリでRedux-Sagaを使ったので,その話 / TOM ...
Search
pochi
September 01, 2017
Programming
2.2k
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
React Nativeで作ったアプリでRedux-Sagaを使ったので,その話 / TOM Internal Developer Session #7
Redux-Sagaの説明周り
pochi
September 01, 2017
More Decks by pochi
See All by pochi
Expoで開発してアプリを公開して得られた知見 / RNM6
pchw
3
1.9k
Firebaseでラクラクリアルタイムアプリ
pchw
0
1.4k
MongoDB族のための組み込み軽量DB NeDB
pchw
0
1.5k
月刊ライトニングトーク2014年8月号: MEAN 祭り資料
pchw
0
4.3k
Synth - 東京Node学園2014
pchw
0
4.4k
RubyMotion 1.15で追加されたtest周りの話
pchw
1
3.2k
Other Decks in Programming
See All in Programming
RTSPクライアントを自作してみた話
simotin13
0
520
Copilot CLI の継戦能力を高める コンテキスト管理
nozomutu
1
1.2k
TSKaigi Night Talks 2026_TypeScriptでサプライチェーンの整合性を型に閉じ込める
geekplus_tech
0
330
ECSアプリログをFireLensでコスト削減しようとしたけど諦めた話 in Fargate×Node.js
akihisaikeda
2
4k
TAKTでAI駆動開発の品質を設計する
j5ik2o
6
1.1k
ユニットテストの先へ:テスト技法で要求・仕様を整理するJava開発実践 / Beyond_Unit_Testing_Practical_Java_Development_Techniques_for_Organizing_Requirements_and_Specifications
shimashima35
0
390
[2026年度第1回ORセミナー] 計画最適化ベンチャーと競技プログラミング人材
terryu16
0
250
コンテキストの使い捨てをやめる — ビジネスルール駆動開発と miko —
ioki
0
180
Vue × Nuxt × Oxc どこまで使える?実運用の現在地
andpad
0
150
決定論的オーケストレーションの設計と実装 / Design and Implementation of Deterministic Orchestration
nrslib
3
1.3k
「エンジニアインターン、どうやって取った?」準備のリアルを語るLT会 Progate BAR
akiomatic
0
130
Old Dog, New Tricks: The Java 25 Reinvention - JNation
bazlur_rahman
0
150
Featured
See All Featured
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
31
3.2k
Effective software design: The role of men in debugging patriarchy in IT @ Voxxed Days AMS
baasie
0
400
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
141
35k
Intergalactic Javascript Robots from Outer Space
tanoku
273
27k
The Straight Up "How To Draw Better" Workshop
denniskardys
239
140k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
55k
Leo the Paperboy
mayatellez
7
1.8k
Practical Orchestrator
shlominoach
191
11k
The Cost Of JavaScript in 2023
addyosmani
55
10k
Impact Scores and Hybrid Strategies: The future of link building
tamaranovitovic
0
300
Dealing with People You Can't Stand - Big Design 2015
cassininazir
367
27k
SERP Conf. Vienna - Web Accessibility: Optimizing for Inclusivity and SEO
sarafernandez
2
1.5k
Transcript
React Native でRedux‑Saga を使ったりした 話 Tokyo Otaku Mode Internal Developers
Sesssion Aug 25, 2017 Hiroshi HORIKI @pchw
React Native で最近作ったアプリたち
React Native React の技術を使って,Native アプリを作れる シンプルなアプリを作るだけなら, 特にフレー ムワー クを入れる必要な く作れる.
アー キテクチャ導入の決定 「 アプリが複雑になることが決まっている」 「 そろそろ状態管理が辛くなってきた」 「 非同期の処理が多くなってきて, 特定のstate をどこの処理が変更
しているかわからなくなってきた」
Flux アー キテクチャ
Redux Flux 実装の1 つ 1 方向のデー タの流れ グロー バルな一つのImmutable State
上図のような概念を導入できる.
Redux 実装者が用意する必要があるのは, Action の一覧 Reducer というAction の種類によってState を更新し新しいState を 生成する処理
初期State の値 View であるComponent State を変更したい時にdispatch でAction を送出するようにする
Redux import { createStore } from 'redux'; import reducers from
'./reducers' const initialState = {...}; const store = createStore( reducers, initialState ); のようにして,Reducer と初期State の値を元にStore を作る. store.dispatch() とすれば, reducers がハンドリングして新しい State が生成されてStore の中身が更新される.
React‑Redux react‑redux というモジュー ルを入れることで, View である Component に Store へのアクセスやAction
をdispatch するための仕組 みを導入することができる. import { connect } from 'react‑redux'; class HogeComponent extends React.Component { render(){ const { somethingStateField, dispatch } = this.props; dispatch({type: ACTION_TYPES.HOGE_RENDERED}); } } export default connect(mapStateToProps)(HogeComponent)
React‑Redux トップレベルのComponent は特別に Provider というComponent で囲 んであげて, createStore で生成したstore をプロパティとして渡す必
要があります. import { Provider } from 'react‑redux'; import Hoge from './HogeComponent' export default class App extends Component { render() { return ( <Provider store={store}> <Hoge/> </Provider> ); } }
( やっと) Redux‑Saga の話
Redux‑Saga API 連携とかの機能が付いてくると, 非同期で処理を行い, その結果をま た別のAPI に投げて・・・ ということがあり, そこで導入すると良いの が
Redux‑Saga . Reducer Action で投げられたタイプによってState を変えて新しいState を作り出す 複雑な処理は行ってはならない Redux‑Saga Action で投げられたタイプによって処理を行い副作用を起こす 副作用をStore に反映するのはdispatch 経由.
Redux‑Saga
Redux‑Saga Action の待受は yield takeEvery(ACTION_TYPE_XXX, doSomethingX); yield takeEvery(ACTION_TYPE_YYY, doSomethingY); yield
takeEvery(ACTION_TYPE_ZZZ, doSomethingZ); みたいにする.
Redux‑Saga は何が嬉しいのか? generator を活用して書くため, 全て同期的に書ける 並行してのAction の待ち受けや,2 回目にAction が飛んできたら別 の処理をしたいということも簡単.
処理と処理を完全に分離して書ける API の呼び出しやState の取得・ 変更もRedux‑Saga のgenerator 関 数を経由して書くため, 処理をモックすることなくテストを簡潔に 書くことが出来る
Redux‑Saga の世界 redux‑saga/effects に色んなsaga の世界観を実現するためのAPI が 用意されている take fork select
call put を覚えておけば, 基本的なケー スに対応できる.
Redux‑Saga を使う準備 Redux 時代のコー ドから createStore のところを変更 import { createStore,
applyMiddleware } from 'redux'; import createSagaMiddleware from 'redux‑saga'; import rootSaga from './sagas'; const sagaMiddleware = createSagaMiddleware(); const store = createStore( reducers, initialState, applyMiddleware(sagaMiddleware) ); sagaMiddleware.run(rootSaga);
Redux‑Saga を使う準備 redux‑saga/effects から使うものをimport する. import { take, fork, select,
call, put, takeEvery, takeLatest} from 'redux‑saga/effects'
take: Action の待受 yield take(ACTION_TYPE_XXXX, doSomethingX); ACTION_TYPE_XXX を待ち受けて, doSomethingX を実行する.
待ち受けたり, 実行してる間には, 他のイベントを取りこぼす. 順次処理を行う時は, yield take(ACTION_TYPE_START_STAGE, startStageOne); yield take(ACTION_TYPE_START_STAGE, startStageTwo); みたいにすると,1 つ目の take が終わったら2 つ目の take で待受にな るので, 同じイベントでも2 回目で処理を変える( この場合はステー ジ2 が始まる) ことができる.
fork: 平行世界を作る 前述の take だけだと, 並行してAction を待ち受けず, 処理している間 にAction を取りこぼしたりする.
そこで, fork を使う.
fork: 平行世界を作る yield fork(function*(){ yield take(ACTION_TYPE_START_STAGE, startStageOne); }) yield fork(function*(){
yield take(ACTION_TYPE_ENCOUNT_CHALLENGER, encountChallenger); }) のようにすると, yield fork はすぐに制御が返ってきて, 裏では指定 した関数が実行される. 1 つめの fork で ACTION_TYPE_START_STAGE を待ち受ける. fork はすぐに制御を返すので, そのまま2 つめの fork へ進 み, ACTION_TYPE_ENCOUNT_CHALLENGER も待ち受ける. これで, ステー ジの開始のアクションもハンドリング出来るし, 並行し て乱入者が来たかどうかをハンドリングすることも出来る.
takeEvery take は1 度Action を受け取ったらそれで終わり. タップ入力などの何度もAction をハンドリングする必要が有る場合は yield fork(function*(){ while(true){
yield take(ACTION_TYPE_MOVE_LEFT, moveLeft); } }); のように,while ルー プで何度も待ち受けるというようなことをしないと いけない. Redux‑Saga はヘルパー を用意していて, 上記と同様の fork してwhile ルー プで待ち受けるような処理を yield takeEvery(ACTION_TYPE_MOVE_LEFT, moveLeft); と書くだけで実現できる.
takeLatest 検索バー のインクリメンタル検索のように, 次の入力があったら最後の 入力だけで処理をしたいというときに使えるのが takeLatest yield takeLatest( ACTION_TYPE_SEARCH_BAR_CHANGED,searchProduct); イベントのたびに
searchProduct が呼ばれる. 処理中に同じAction が再度飛んできた場合, 前回のタスクをキャンセル して新しく searchProduct を実行する. takeEvery と同様に, fork 作用と while で継続的に待ち受ける機 能も有しているので, 上記のように書くだけで別のAction の待受と並行 で待ち受けることが出来る.
select: Store からstate を読み出す take して実行している関数の中で Store に格納された state が使い
たい場合は select を使って読み出すことが出来る. const searchProduct = function*(){ const state = yield select(); }
call: 非同期の関数を呼び出す 外部にアクセスするAPI などを叩く時などは call を使う const searchProduct = function*(){
const state = yield select(); const result = yield call( API.findProduct, {q: state.searchText}); } テストの簡便さのために, yield API.findProduct({q: state.searchText}) ではなく, call で囲んで呼ぶ. call を経由しないで行う場合は, テスト時に API.findProduct が返 すPromise がどのような状態だとテストがPass なのかが難しく, 外部に アクセスする場合はAPI をモックが必要 call を使うと, タスクのオブジェクトが返り, それを assert すれば テストができる.
put タスク内で得られた結果を Store に反映させたい場合は put を使っ て,Action をdispatch する. 新しいState
を作成し,Store を変更するのはReducer の責務. const searchProduct = function*(){ const state = yield select(); const result = yield call( API.findProduct, {q: state.searchText}); yield put({ type: ACTION_TYPE_SEARCH_COMPLETE, payload:{products: result.products} }); }
図にまとめると
まとめ Redux‑Saga を使うと非同期のややこしい処理が分割出来て同期 的に書けて捗る React Native でも使える 仕組み的には,redux のvue 版であるVuex
などにも応用出来そう?