Download free for 30 days
Sign in
Upload
Language (EN)
Support
Business
Mobile
Social Media
Marketing
Technology
Art & Photos
Career
Design
Education
Presentations & Public Speaking
Government & Nonprofit
Healthcare
Internet
Law
Leadership & Management
Automotive
Engineering
Software
Recruiting & HR
Retail
Sales
Services
Science
Small Business & Entrepreneurship
Food
Environment
Economy & Finance
Data & Analytics
Investor Relations
Sports
Spiritual
News & Politics
Travel
Self Improvement
Real Estate
Entertainment & Humor
Health & Medicine
Devices & Hardware
Lifestyle
Change Language
Language
English
Español
Português
Français
Deutsche
Cancel
Save
Submit search
EN
Uploaded by
TIS Inc
PPTX, PDF
160 views
React+redux+saga 03
TIS Internal Workshop of React/Redux/Redux-Saga 03 You need to download
Software
◦
Read more
0
Save
Share
Embed
Embed presentation
Download
Download to read offline
1
/ 25
2
/ 25
3
/ 25
4
/ 25
5
/ 25
6
/ 25
7
/ 25
8
/ 25
9
/ 25
10
/ 25
11
/ 25
12
/ 25
13
/ 25
14
/ 25
15
/ 25
16
/ 25
17
/ 25
18
/ 25
19
/ 25
20
/ 25
21
/ 25
22
/ 25
23
/ 25
24
/ 25
25
/ 25
More Related Content
PDF
PHP 2大 web フレームワークの徹底比較!
by
Shohei Okada
PPTX
無料静的ホスティング × FaaSの話
by
Shinichi Ueno
PPTX
React+redux+saga 02
by
TIS Inc
PDF
ソーシャルアプリ勉強会(第一回資料)配布用
by
Yatabe Terumasa
PDF
Pro aspnetmvc3framework chap19
by
Hideki Hashizume
PPTX
React+redux+saga 01
by
TIS Inc
PDF
React入門-JSONを取得して表示する
by
regret raym
PDF
Backbone.js
by
daisuke shimizu
PHP 2大 web フレームワークの徹底比較!
by
Shohei Okada
無料静的ホスティング × FaaSの話
by
Shinichi Ueno
React+redux+saga 02
by
TIS Inc
ソーシャルアプリ勉強会(第一回資料)配布用
by
Yatabe Terumasa
Pro aspnetmvc3framework chap19
by
Hideki Hashizume
React+redux+saga 01
by
TIS Inc
React入門-JSONを取得して表示する
by
regret raym
Backbone.js
by
daisuke shimizu
Similar to React+redux+saga 03
PDF
実践 NestJS
by
Ayumi Goto
PDF
ReduxとSwiftの組み合わせ:改訂版
by
Fumiya Sakai
PDF
react勉強会 #3
by
KentaIwadate
PPTX
Rails×React×TS で作るwebアプリ入門【weseek tech conf #10】
by
WESEEKWESEEK
PDF
React+TypeScriptもいいぞ
by
Mitsuru Ogawa
PPTX
React + FLUX + Redux + Redux Saga のお話
by
Shinichiro Yoshida
PDF
Web App Development Flow with Scala and HTMX
by
anatoliikmt
PDF
マッチングアプリ『Omiai』の Flutter へのリプレイスの挑戦 (FlutterKaigi 2024)
by
Kosuke Saigusa
PDF
RailsでReact.jsを動かしてみた話
by
yoshioka_cb
PDF
Fundamentals of Swift & Redux (ReduxとSwiftの組み合わせ)
by
Fumiya Sakai
PDF
東京Node学園#3 Domains & Isolates
by
koichik
PDF
20190731 Azure Functions x Line at Azure Tech Lab #4
by
Issei Hiraoka
PPTX
Reactive Programming
by
maruyama097
PPTX
Reactive
by
Akihiro Ikezoe
PDF
Reactnative はじめの一歩
by
PIXTA Inc.
PPTX
SYSTEMI勉強会まとめ資料(React基礎まとめ)
by
YoshikiWatanabe1
PDF
React.js + Flux入門 #scripty02
by
Yahoo!デベロッパーネットワーク
PDF
サービスの成長を支えるフロントエンド開発 #denatechcon
by
DeNA
PPTX
ReactNative はじめの一歩
by
Ikki Takahashi
PDF
React native実践談
by
Kiyotaka Kunihira
実践 NestJS
by
Ayumi Goto
ReduxとSwiftの組み合わせ:改訂版
by
Fumiya Sakai
react勉強会 #3
by
KentaIwadate
Rails×React×TS で作るwebアプリ入門【weseek tech conf #10】
by
WESEEKWESEEK
React+TypeScriptもいいぞ
by
Mitsuru Ogawa
React + FLUX + Redux + Redux Saga のお話
by
Shinichiro Yoshida
Web App Development Flow with Scala and HTMX
by
anatoliikmt
マッチングアプリ『Omiai』の Flutter へのリプレイスの挑戦 (FlutterKaigi 2024)
by
Kosuke Saigusa
RailsでReact.jsを動かしてみた話
by
yoshioka_cb
Fundamentals of Swift & Redux (ReduxとSwiftの組み合わせ)
by
Fumiya Sakai
東京Node学園#3 Domains & Isolates
by
koichik
20190731 Azure Functions x Line at Azure Tech Lab #4
by
Issei Hiraoka
Reactive Programming
by
maruyama097
Reactive
by
Akihiro Ikezoe
Reactnative はじめの一歩
by
PIXTA Inc.
SYSTEMI勉強会まとめ資料(React基礎まとめ)
by
YoshikiWatanabe1
React.js + Flux入門 #scripty02
by
Yahoo!デベロッパーネットワーク
サービスの成長を支えるフロントエンド開発 #denatechcon
by
DeNA
ReactNative はじめの一歩
by
Ikki Takahashi
React native実践談
by
Kiyotaka Kunihira
React+redux+saga 03
1.
React + Redux
+ Redux-Saga 勉強会 ③ Redux-Saga編 2019/8/5 tashxii@tis https://fintan.jp/
2.
React / Redux
/ Redux-Saga • React … UIライブラリ • Redux … React の状態管理ライブラリ • Redux-Saga … 非同期処理を扱うReduxのミドルウェア 2 https://ja.reactjs.org/ https://Redux-Saga.js.org/ https://redux.js.org/ Skip可:前回と同じスライド
3.
題材に使うアプリケーション • タスク管理アプリ • イメージ(gif) •
機能 • サインアップ • ログイン • ボード管理 • ユーザー管理 • タスク管理 • ドラッグ&ドロップ • Push通知 3 Skip可:前回と同じスライド
4.
題材に使うアプリケーション • Websocketを使ったPush通知 • イメージ(gif) •
他のクライアントの 操作をサーバー 経由で伝達 4 Skip可:前回と同じスライド
5.
題材のアプリで使用しているライブラリ • Redux 状態管理ライブラリ •
Redux-Saga 非同期処理用ライブラリ • styled-component コンポーネントのスタイル管理 • Ant design コンポーネントライブラリ • react-beautiful-dnd ドラッグ&ドロップコンポーネント • react-router-dom URL遷移 • Font awesome アイコンライブラリ 5 Skip可:前回と同じスライド
6.
ソースコード • Front-end (React) https://github.com/tashxii/taskboard-react •
Back-end (Go) https://github.com/tashxii/taskboard-api-go git clone https://github.com/tashxii/taskboard-react.git cd taskboard-react yarn install git clone https://github.com/tashxii/taskboard-api-go.git cd taskboard-api-go dep ensure go build 6 Skip可:前回と同じスライド
7.
Reactとは(ダイジェスト) 7 Skip可:前回と同じスライド
8.
Reactを使うアプリケーションの構成 https://ja.reactjs.org/8 • Reactは、Viewを提供するライブラリであり、それ以外の技術スタックを 組み合わせて使うことが前提 以下のような組み合わせで使う • Redux
… アプリケーションの状態管理フレームワークを使用したり、 • Redux-Saga … 非同期処理を扱うライブラリを使ったり、 • Back-end サーバー(RESTやSOAPサーバー)と組み合わせて構成する ここを取り上げます
9.
非同期処理 - Redux-Saga 9
10.
Redux-Sagaとは? • 非同期処理を扱うReduxのmiddleware • 非同期処理をコールバック等を使わず 手続的に記述することができる 10 https://redux-saga.js.org/
11.
同期処理との違い • 同期処理では、「ログイン」は、ログインボタン押下⇒待ち⇒ログイン後の 処理の継続のような流れになる • 非同期処理は、「開始」、「成功」、「失敗」の三つに分岐される •
「開始」後にコントロールがユーザーに返されるため、二重サブミット防止や、処理 中が分かるような表示へのフィードバックなどをする必要がある 11 export const UPDATE_LOGIN_USER_START_EVENT = "UPDATE_LOGIN_USER_START_EVENT" export const UPDATE_LOGIN_USER_SUCCESS_EVENT = "UPDATE_LOGIN_USER_SUCCESS_EVENT" export const UPDATE_LOGIN_USER_FAILURE_EVENT = "UPDATE_LOGIN_USER_FAILURE_EVENT“ export const LOGOUT_START_EVENT = "LOGOUT_START_EVENT" export const LOGOUT_SUCCESS_EVENT = "LOGOUT_SUCCESS_EVENT" export const LOGOUT_FAILURE_EVENT = "LOGOUT_FAILURE_EVENT"
12.
Saga Middlewareの登録 • createSagaMiddleware
を使用して ReduxのMiddlewareに登録 12 import React from "react" import { render } from "react-dom" import { Provider } from "react-redux" import { createStore, applyMiddleware } from "redux" import createSagaMiddleware from "redux-saga" import App from "./components/App" import appState from "./reducers" import rootSaga from "./sagas/saga" const sagaMiddleware = createSagaMiddleware() const store = createStore( appState, applyMiddleware(sagaMiddleware) ) sagaMiddleware.run(rootSaga) render( <Provider store={store}> <App /> </Provider>, document.getElementById("root") ) forkした 関数をrun
13.
forkを使用してハンドラを登録 • fork を使用してハンドラ 関数を登録 13 import
{ fork } from "redux-saga/effects" import UserSagas from "./userSagas" import BoardSagas from "./boardSaga" import TaskSagas from "./taskSaga" import WsSaga from "./wsSaga" export default function* rootSaga() { let sagaFunctions = [] sagaFunctions = sagaFunctions.concat(UserSagas.sagaFunctions()) sagaFunctions = sagaFunctions.concat(BoardSagas.sagaFunctions()) sagaFunctions = sagaFunctions.concat(TaskSagas.sagaFunctions()) sagaFunctions = sagaFunctions.concat(WsSaga.sagaFunctions()) for (let i = 0; i < sagaFunctions.length; i++) { yield fork(sagaFunctions[i]) } } function* handleListUsers() { yield takeEvery(LIST_USERS_START_EVENT, listUsers) } function* listUsers(/*action*/) { const { users, error } = yield call(UserService.listAsync) if (!error) { yield put(listUsersSuccessEvent(users)) } else { yield put(listUsersFailureEvent(error)) } } export default class UserSagas { static sagaFunctions = () => { return [ handleLogin, handleSignUp, handleLogout, handleUpdateLoginUser, handleListUsers, ] } } ハンドラ関数 fork
14.
基本的な流れ • takeEveryでユーザーの操作から 呼ばれるイベントを待ち受ける • callで非同期処理を呼び出す •
putで次のイベントを起こす 14 function* handleLogin() { yield takeEvery(LOGIN_START_EVENT, login) } function* login(action) { const payload = action.payload const { user, error } = yield call( UserService.loginAsync, payload.name, payload.password) if (!error) { yield put(loginSuccessEvent(user)) } else { yield put(loginFailureEvent(error)) } } イベント 待ち受け 非同期 呼び出し 次の イベント クリック イベントを 待つ
15.
双方向通信(Push通知) • eventChannel を作成し、 •
サーバーからのメッセージに 対応したイベントを emit する • クライアントのイベントは、takeで 監視する • サーバーのイベントはチャンネルを 作り、それを take で監視する 15 const createWebsocketChannel = async loginUser => { return eventChannel(emit => { const ws = ApiCommon.createWebsocket(loginUser) ws.onmessage = (msg) => { const params = msg.data.split(" ") if (params.length >= 1) { const type = params[0] let ids = params.slice(1) switch (type) { case "UPDATE_TASKBOARDS": { ids.forEach(boardId => { emit(listTasksStartEvent(boardId)) }) break } case "UPDATE_BOARDS": break default: break } } } return () => { // Nothing } }) } イベント チャンネル サーバーからのメッ セージに対応した イベントをemit
16.
双方向通信(Push通知) • サーバーからのメッセージを eventChannel
で受け付け、 • channel を take し、そのアクションを put する 16 function* handleWebsocketMessage() { yield takeEvery(LOGIN_SUCCESS_EVENT, watchWebsocketMessage) } function* watchWebsocketMessage(action) { const channel = yield call(createWebsocketChannel, action.payload.user) while (true) { const pushedAction = yield take(channel) yield put(pushedAction) } } Channelをcall で作成する channelをtakeして そのイベントをputする
17.
レイヤー設計 17
18.
レイヤー設計 • Redux, Redux-Sagaを使う場合、ビジネスロジック=状態遷移はreducers, saga関数内で実装される •
何もしないでロジックを書いていくとreducers, sagaが肥大化していって しまう • 以下のようなレイヤー設計を導入して対応する方法がある • 表示用のmodel層を作成する • ロジックを集約するservice層を設ける • API層を作成し、APIのリクエストとレスポンスをmodelと切り分ける • “Converter”を用いて、modelとAPIのリクエストとレスポンスを変換する 18
19.
View レイヤー設計(全体) 19 Reducer/Saga Service Layer API Layer Component Model Store Converter Model Request/ Response API以外の 全てから参照 Serviceを 呼び出す Modelと Request/Response を変換する Request/ Response
20.
レイヤー設計(Model) • ES2015のclassとして作成 • StoreやComponentで参照する 20 export
default class Board { constructor( id, name, dispOrder, isSystem, isClosed, createdDate, version, tasks, ) { this.id = id this.name = name this.dispOrder = dispOrder this.isSystem = isSystem this.isClosed = isClosed this.createdDate = createdDate this.version = version this.tasks = tasks } } export default class Task { constructor( id, name, description, assigneeUserId, boardId, dispOrder, createdDate, isClosed, estimateSize, version, ) { this.id = id this.name = name this.description = description this.assigneeUserId = assigneeUserId this.boardId = boardId this.dispOrder = dispOrder this.createdDate = createdDate this.isClosed = isClosed this.estimateSize = estimateSize this.version = version } } export default class User { constructor(id, name, avatar, version) { this.id = id this.name = name this.avatar = avatar this.version = version this.newPassword = "" } } User Task Board
21.
レイヤー設計(Saga) • Serviceを呼び出すのみ 21 function* handleCreateTask()
{ yield takeEvery(CREATE_TASK_START_EVENT, createTask) } function* createTask(action) { const payload = action.payload const { task, error } = yield call(TaskService.createAsync, payload.task) if (!error) { yield put(createTaskSuccessEvent(task)) } else { yield put(createTaskFailureEvent(error)) } } Serviceの 呼び出し タスクの作成
22.
レイヤー設計(Service) • APIを呼び出す • Converterを使い、RequestとResponse
⇔ Model の変換を行う 22 export default class TaskService { static createAsync = async (taskCreateRequest) => { const request = TaskConverter.convertCreateRequest(taskCreateRequest) return await TaskApi.create(request) .then((res) => { if (res.ok) { return { task: TaskConverter.getTaskByTaskResponse(res.json) } } else { return { error: ApiErrorConverter.createByApiError(res, I18n.get("タスクの登録に失敗しました")) } } }) .catch((error) => { return { error: ApiErrorConverter.createSystemError(error) } }) } Task ⇒ TaskCreateRequest 変換 TaskService.js Response ⇒ Task 変換
23.
レイヤー設計(Converter) • ModelをResponseとRequestに変換 (REST API
ならJSONをclassにする) • APIの変更を吸収する 23 export default class TaskConverter { static getTaskByTaskResponse = (response) => { return new Task( response.id, response.name, response.description, response.assigneeUserId, response.boardId, response.dispOrder, response.createdDate, response.isClosed, response.estimateSize, response.version, ) } static convertCreateRequest = (task) => { return { name: task.name, description: task.description, assigneeUserId: task.assigneeUserId, boardId: task.boardId, dispOrder: task.dispOrder, isClosed: task.isClosed, estimateSize: task.estimateSize, } } TaskConverter.js Response ⇒ Task 変換 Task ⇒ TaskCreateRequest 変換
24.
レイヤー設計(API) • Httpメソッドを呼び出す(fetch API使用) 24 export
default class TaskApi { static create = async (request) => { return await ApiCommon.post("/tasks", request) } static list = async (boardId) => { return await ApiCommon.get(`/tasks?boardid=${boardId}`) } static get = async (taskId) => { return await ApiCommon.get(`/tasks/${taskId}`) } static update = async (taskId, request) => { return await ApiCommon.put(`/tasks/${taskId}`, request) } static delete = async (taskId) => { return await ApiCommon.delete(`/tasks/${taskId}`, {}) } } TaskAPI.js GET, POST, PUT, DELETE を呼び出す export default class ApiCommon { static async get(path) { return doFetch( getApiUrl(path), getOption() ) } static async post(path, request) { return doFetch( getApiUrl(path), getUpdateOption(ApiCommon.Method.POST, request) ) } static async put(path, request) { return doFetch( getApiUrl(path), getUpdateOption(ApiCommon.Method.PUT, request) ) } static async delete(path, request) { return doFetch( getApiUrl(path), getUpdateOption(ApiCommon.Method.DELETE, request) ) } } const doFetch = async (path, option) => { let ok = false let status = -1 return await fetch(path, option) .then(response => { ok = response.ok status = response.status return response.text() }) .then(text => { const json = text !== "" ? JSON.parse(text) : {} return { ok, status, json } }) .catch(error => { throw error }) } } APICommon.js
25.
覚えていてほしいこと • Redux-Sagaでの基本的な流れ • takeEvery
… イベントの待ち受け • call … 非同期処理の呼び出し • put … イベントの発行 • Redux-SagaでのPush通知 • eventChannel と emit • eventChannel のtake • レイヤー化設計があること • Serviceにロジックを集約する • APIとビューを疎結合にする 25
Download