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-Redux-Redux-Saga-Workshop01
Search
tashxii
July 22, 2019
Programming
0
100
React-Redux-Redux-Saga-Workshop01
From TIS internal workshop at 2019/7/22
tashxii
July 22, 2019
Tweet
Share
More Decks by tashxii
See All by tashxii
React-Redux-Redux-Saga-Workshop04
tashxii
0
47
React-Redux-Redux-Saga-Workshop03
tashxii
0
170
React-Redux-Redux-Saga-Workshop02
tashxii
0
120
Other Decks in Programming
See All in Programming
Benchmark
sysong
0
270
Goで作る、開発・CI環境
sin392
0
160
すべてのコンテキストを、 ユーザー価値に変える
applism118
2
950
既存デザインを変更せずにタップ領域を広げる方法
tahia910
1
240
Is Xcode slowly dying out in 2025?
uetyo
1
220
なぜ「共通化」を考え、失敗を繰り返すのか
rinchoku
1
590
git worktree × Claude Code × MCP ~生成AI時代の並列開発フロー~
hisuzuya
1
510
Create a website using Spatial Web
akkeylab
0
310
コードの90%をAIが書く世界で何が待っているのか / What awaits us in a world where 90% of the code is written by AI
rkaga
48
31k
LT 2025-06-30: プロダクトエンジニアの役割
yamamotok
0
590
High-Level Programming Languages in AI Era -Human Thought and Mind-
hayat01sh1da
PRO
0
610
アンドパッドの Go 勉強会「 gopher 会」とその内容の紹介
andpad
0
270
Featured
See All Featured
The Art of Programming - Codeland 2020
erikaheidi
54
13k
Side Projects
sachag
455
42k
Embracing the Ebb and Flow
colly
86
4.7k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
53k
Build your cross-platform service in a week with App Engine
jlugia
231
18k
How STYLIGHT went responsive
nonsquared
100
5.6k
[RailsConf 2023] Rails as a piece of cake
palkan
55
5.6k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
357
30k
Learning to Love Humans: Emotional Interface Design
aarron
273
40k
Code Review Best Practice
trishagee
68
18k
Practical Orchestrator
shlominoach
188
11k
The Straight Up "How To Draw Better" Workshop
denniskardys
234
140k
Transcript
React + Redux + Redux-Saga 勉強会 ① 概要編 2019/7/22 tashxii@tis
https://fintan.jp/
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/
題材に使うアプリケーション • タスク管理アプリ • イメージ(gif) • 機能 • サインアップ •
ログイン • ボード管理 • ユーザー管理 • タスク管理 • ドラッグ&ドロップ 3
題材のアプリで使用しているライブラリ • Redux 状態管理ライブラリ • Redux-Saga 非同期処理用ライブラリ • styled-component コンポーネントのスタイル管理
• Ant design コンポーネントライブラリ • react-beautiful-dnd ドラッグ&ドロップコンポーネント • react-router-dom URL遷移 • Font awesome アイコンライブラリ 4
ソースコード • 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 5
Reactとは • Facebook製のJSライブラリ • Viewに特化しているフロントエンドライブラリ • Github スター数 13.3k https://ja.reactjs.org/
6
Popular Front-end Frameworks • 2018年のhttps://2018.stateofjs.com/front-end-frameworks/overview/ 調べ 今使っているが、 また使いたい 今使っているが もう使いたくない
聞いたことがあり、 習いたい 聞いたことはある が、興味はない 聞いたことはある が、興味はない React Vue Angular 7
特徴 • Virtual DOM(仮想)による直感的なUI実装 • コードとHTML要素をミックスして記述 • コンポーネント指向 • 豊富なライブラリやコンポーネントが存在
• 自身のコンポーネントを簡単に作成 <div> <Row style={{ marginTop: "10px" }}> <Col style={{ float: "right", marginRight: "5px" }}> <Button type="primary" onClick={this.toggleNewTaskDialog} disabled={spininig} > {I18n.get("新しいタスク")} </Button> </Col> <Col style={{ float: "right", marginRight: "5px" }}> <Input placeholder={I18n.get("タスクのフィルター")} onChange={(e) => this.handleTaskFilterChange(e)} disabled={spininig} allowClear /> </Col> </Row> <Row style={{ marginTop: "2px" }}> { boards.map(board => { return ( <BoardLane key={board.id} board={board} taskFilter={this.state.taskFilter} {...this.props} /> ) }) } </Row> </div> タグとコードがミックス 8
どんなことができる? • Gmailや、Twitter、FacebookなどのSPA(Single Page Application)を構 成できる • リッチなユーザー体験をもたらすUIを提供できる • React-NativeやElectronなどと併用することで、フロントエンド技術だけ
でWebページと同様な多様さを持つネイティブアプリケーションを開発で きる 9
どんな構成で使う? • Reactは、Viewを提供するライブラリであり、それ以外の技術スタックを 組み合わせて使うことが前提 以下のような組み合わせで使う • Redux … アプリケーションの状態管理フレームワークを使用したり、 •
Redux-Saga … 非同期処理を扱うライブラリを使ったり、 • Back-end サーバー(RESTやSOAPサーバー)と組み合わせて構成する 10
プロジェクトを作る (create-react-app) 11
create-react-app • Front-endの技術スタックは組み合わせが複雑で管理が大変 • babel, webpack, browserify, jest, … •
Facebook製のプロジェクト作成ツールを使えば簡単に作成可能 • create-react-app • npx • npm • yarn https://facebook.github.io/create-react-app/docs/getting-started 12 npx create-react-app my-app npm init react-app my-app yarn create react-app my-app
Virtual DOM(仮想DOM) 13
コンポーネントのルール • Reactの2通りの定義方法がある • React.Componentを継承したクラスを作成する方法 • ライフサイクルやstateを持つ場合 • 純粋なrender関数として定義する方法 •
どちらでもrender関数は1つのHTMLのDOM要素を返すことがルール になっている。 const Avatar = (props) => { const setting = ApplicationSetting.getServerSetting() const src = `${setting.url}/${setting.base}/${setting.img}/${props.avatar}${setting.ext}` const size = props.size || "50px" const alt = props.alt || "No Image" return ( <img src={src} width={size} height={size} borderstyle={"solid"} border={"thin solid gray"} align={"center"} alt={alt} /> ) } class MainPage extends Component { render() { return ( <MainPageTemplate {...this.props} /> ) } } 14
propsとstate • コンポーネントは、以下の2つの状態を持つ。 • props … 親のコンポーネントから渡される読み取り専用の値 • 親から渡されるオブジェクトやコールバックなどを持つ。 •
state … 自身のコンポーネントで持つ、編集可能な値 • チェックボックスや入力中のフィールド値などを持ち、setStateで更新する。 class MenuBar extends Component { constructor(props) { super(props) this.state = { showProfileDialog: false } this.toggleProfileDialog = this.toggleProfileDialog.bind(this) } render() { const loginUserName = this.props.loginState.loginUser.name || "" const avatarName = this.props.loginState.loginUser.avatar || "" return ( // ... 15
変数を使うには? • .jsxの中では、「{」と「}」で括って変数やプログラミング要素を記述する。 class LoginForm extends Component { constructor(props) {
super(props) this.state = { name: "", password: "", showSignUpDialog: false, } this.handleTextChange = this.handleTextChange.bind(this) this.toggleSignUpDialog = this.toggleSignUpDialog.bind(this) } render() { const loginLabel = (!this.props.loginState.isLoginProcessing) ? I18n.get("ログイン") : I18n.get("ログイン中") const disabled = this.props.loginState.isLoginProcessing || this.state.name === "" return ( <div> <Col> <Row> <div style={{ fontSize: "32px" }}> <font color="cornflowerblue">Taskboard React</font> </div> </Row> // ... 16
if文を使うには? • 「{」と「}」の中でif文を書く。 • 三項演算子を使う。 • (cond) ? <DOM/> :
null である条件の時だけDOMを 表示する class ErrorCard extends Component { render() { const errorMessage = this.props.errorMessage const summary = errorMessage.summary const summaryColor = this.props.summaryColor || "red" const detailColor = this.props.detailColor || "gray" let detail = "" if (errorMessage.detail) { detail = (errorMessage.code) ? `${errorMessage.detail}(${errorMessage.code})` : `${errorMessage.detail}` } return ( <div style={this.props.cardStyle}> <div> <font color={summaryColor}> {summary} </font> </div> {(detail) ? <div> <font color={detailColor}> {detail} </font> </div> : null} </div> ) } } 17
forループを使うには? • 配列要素で、render関数(DOM要素を 返す関数)を記述することができる。 class BoardLane extends Component { render()
{ return ( <Lane> <TaskList style={styles}> { tasks.map((task) => { return ( <TaskCard key={task.id} index={task.dispOrder} task={task} taskUser={userMap[task.assigneeUserId]} onEditButtonClick={this.props.onUpdateTaskButtonClick} onDeleteButtonClick={this.props.onDeleteTaskButtonClick} isSavingProcessing={this.props.tasksState.isSavingTask} users={this.props.usersState.users} boards={this.props.boardsState.boards} /> )}) } </TaskList> </Lane> ) } } tasks.map((task)=>{ return <DOM要素> }) 18
自身のコンポーネントの状態を変えるには? • this.setState関数でstateを変更することができる • setStateを呼び出すと再描画(renderの呼び出し)がされる class LoginForm extends Component {
constructor(props) { super(props) this.state = { name: "", password: "", showSignUpDialog: false, } this.handleTextChange = this.handleTextChange.bind(this) this.toggleSignUpDialog = this.toggleSignUpDialog.bind(this) } ダイアログの表示フラグ 19 toggleSignUpDialog() { this.props.clearLoginErrors() this.setState({ showSignUpDialog: !this.state.showSignUpDialog, }) } フラグの切り替え
親のコンポーネントの状態を変えるには? • コールバックを呼び出すことで、reducerを通してpropsや親のstateを変 えることができる。 <Modal visible={this.state.showEditTaskDialog} onCancel={this.toggleEditTaskDialog} footer={null} destroyOnClose width={500}
> <TaskForm mode={TaskForm.Mode.Edit} task={task} users={this.props.users} boards={this.props.boards} onSaveButtonClick={this.props.onEditButtonClick} isSavingProcessing={this.props.isSavingProcessing} /> </Modal> タスク表示 コンポーネント ダイアログのOKボタンで コンテナのタスク変更 関数が呼び出される 20
状態管理 - Redux 21
アプリケーションの状態管理 • Reduxというライブラリを使用して管理する • React だけでも出来るが、一定規模以上でライブラリを使用しないのは管理が困難 • Redux • 「Store」と呼ばれる状態をアプリケーション全体で管理する
• 状態は細分化して保持することもできる • Fluxと呼ばれるアーキテクチャの実装がRedux 22
Fluxアーキテクチャ • MVVMの双方向バイン ディングなどと異なり、 ビューモデルが「単一方 向」で更新されるアーキテ クチャ • 右はイメージ(gif) •
View(コンポーネント)と Reducers(状態遷移)を 実装すればアプリの 画面が更新される 23 http://slides.com/jenyaterpil/redux-from-twitter-hype-to-production#/27
Redux – Store / Component • Store • アプリケーション全体の状態を表す •
combineReducers を使って小さな状態の集まりに粒度化できる • Component • JSXで書かれたコンポーネント • 親から渡される読み取り専用のpropsと自身が持ち書き込み可能な stateを持つ 24
Redux – Action / Reducers • Action / ActionCreater •
UIやAPI呼び出しなどのイベント定義 • typeとpayloadと呼ばれるパラメータを持つ • Reducer • 状態を遷移させる純粋関数群 • 古い状態から新しい状態を作成する • Actionのtypeのcaseに応じて処理を書く • combineReducerというAPIで細粒度化可能 25 export const LOGIN_START_EVENT = "LOGIN_START_EVENT" export const loginStartEvent = (name, password) => ({ type: LOGIN_START_EVENT, payload: { name, password, } })
Redux – Container • Container • コンポーネントと状態、Action の関数を接続させる役割を持 つ •
mapStateToPropsでStoreの stateをマッピングし、 mapDispatchToPropsでAction イベント関数をdispatchする • mapStateToPropsと mapDispatchToPropsを connect関数で接続する 26 import { connect } from "react-redux" import { withRouter } from "react-router-dom" import LoginPage from "../components/pages/LoginPage" import { loginStartEvent, signUpStartEvent, clearLoginErrorsEvent, } from "../actions" const mapStateToProps = (state) => ({ loginState: state.loginState, }) const mapDispatchToProps = (dispatch) => ({ onLoginButtonClick: (name, password) => { dispatch(loginStartEvent(name, password)) }, onSignUpButtonClick: (userCreateRequest) => { dispatch(signUpStartEvent(userCreateRequest)) }, clearLoginErrors: () => { dispatch(clearLoginErrorsEvent()) }, }) const LoginContainer = connect( mapStateToProps, mapDispatchToProps, )(LoginPage) export default withRouter(LoginContainer) 画面からのcallback関数 とdispatchのマップ アプリケーション全 体の状態の一部と マップ
タスク管理アプリの状態 • 以下の状態を定義&管理 • ログイン情報 • ボード一覧 • ユーザー一覧 •
ボードごとのタスク一覧 • エラー情報 27 ログイン情報 ボード一覧 ボードごとの タスク一覧 ユーザー一覧 エラー情報
Redux - storeのindex.js • combineReducersという関数で状態をマージ 28 import { combineReducers }
from "redux" import loginState from "./loginState" import mainState from "./mainState" import boardsState from "./boardsState" import tasksState from "./tasksState" import usersState from "./usersState" import errorState from "./errorState" const appState = combineReducers({ loginState, mainState, boardsState, tasksState, usersState, errorState, }) export default appState ログインユーザーオブジェクト ログイン中フラグ ログアウト中フラグ ・・・ ボードID-タスク配列のマップ 新規タスク作成中状態 タスク移動中フラグ ・・・
非同期処理 - Redux-Saga 29
Redux-Saga • Redux-Saga とは、非同期処理を取 り扱うReduxのミドルウェアライブラリ • 非同期処理を手続型で記述すること が可能 • App.jsxで、applyMiddlewareを行う
ことで利用可能 30 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") )
Redux-Sagaの基本 • 非同期処理のイベントは、「Xxx開始」、「Xxx成功」、「Xxx失敗」の3つに分かれる • 画面イベントを受け取るジェネレーター関数を fork することでイベントを監視 • イベントは、takeEvery, call,
putで処理される • takeEvery … イベントの待ち受け • call … 非同期処理の呼び出し • put … 次のイベントの実行 31 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)) } } 待ち受け 非同期呼び出し 次のイベント実行 export default function* rootSaga() { let sagaFunctions = [] sagaFunctions = sagaFunctions.concat(UserSagas.sagaFunctions()) sagaFunctions = sagaFunctions.concat(BoardSagas.sagaFunctions()) sagaFunctions = sagaFunctions.concat(TaskSagas.sagaFunctions()) for (let i = 0; i < sagaFunctions.length; i++) { yield fork(sagaFunctions[i]) } } イベントハンドラ (ジェネレータ関数)の登録 イベントハンドラ (ジェネレータ関数)
覚えていてほしいこと • React というUIのためのJSライブラリ • Virtual DOM = UI記述のための拡張JSと、コンポーネント指向という特徴を持つ •
Redux … アプリケーションの状態管理のReactのためのライブラリ • Redux-saga … 非同期処理を扱うReduxのミドルウェア • create-react-app で簡単にアプリケーションの雛形が作れる 32