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-Workshop02
Search
tashxii
July 30, 2019
Programming
0
120
React-Redux-Redux-Saga-Workshop02
From TIS internal workshop at 2019/7/30
tashxii
July 30, 2019
Tweet
Share
More Decks by tashxii
See All by tashxii
React-Redux-Redux-Saga-Workshop04
tashxii
0
50
React-Redux-Redux-Saga-Workshop03
tashxii
0
170
React-Redux-Redux-Saga-Workshop01
tashxii
0
100
Other Decks in Programming
See All in Programming
複雑なフォームに立ち向かう Next.js の技術選定
macchiitaka
2
220
GitHubとGitLabとAWS CodePipelineでCI/CDを組み比べてみた
satoshi256kbyte
4
250
Deep Dive into Kotlin Flow
jmatsu
1
370
CloudflareのChat Agent Starter Kitで簡単!AIチャットボット構築
syumai
2
510
Improving my own Ruby thereafter
sisshiki1969
1
160
Android 16 × Jetpack Composeで縦書きテキストエディタを作ろう / Vertical Text Editor with Compose on Android 16
cc4966
2
260
テストカバレッジ100%を10年続けて得られた学びと品質
mottyzzz
2
610
Updates on MLS on Ruby (and maybe more)
sylph01
1
180
1から理解するWeb Push
dora1998
7
1.9k
RDoc meets YARD
okuramasafumi
4
170
ぬるぬる動かせ! Riveでアニメーション実装🐾
kno3a87
1
230
「手軽で便利」に潜む罠。 Popover API を WCAG 2.2の視点で安全に使うには
taitotnk
0
870
Featured
See All Featured
Mobile First: as difficult as doing things right
swwweet
224
9.9k
How STYLIGHT went responsive
nonsquared
100
5.8k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
667
120k
A better future with KSS
kneath
239
17k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
48
9.7k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
33
2.4k
Fireside Chat
paigeccino
39
3.6k
Reflections from 52 weeks, 52 projects
jeffersonlam
352
21k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
139
34k
The Illustrated Children's Guide to Kubernetes
chrisshort
48
50k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
358
30k
GraphQLとの向き合い方2022年版
quramy
49
14k
Transcript
React + Redux + Redux-Saga 勉強会 ② Redux編 2019/7/30 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/ Skip可:前回と同じスライド
題材に使うアプリケーション • タスク管理アプリ • イメージ(gif) • 機能 • サインアップ •
ログイン • ボード管理 • ユーザー管理 • タスク管理 • ドラッグ&ドロップ • Push通知 3 Skip可:前回と同じスライド
題材に使うアプリケーション • Websocketを使ったPush通知 • イメージ(gif) • 他のクライアントの 操作をサーバー 経由で伝達 4
題材のアプリで使用しているライブラリ • Redux 状態管理ライブラリ • Redux-Saga 非同期処理用ライブラリ • styled-component コンポーネントのスタイル管理
• Ant design コンポーネントライブラリ • react-beautiful-dnd ドラッグ&ドロップコンポーネント • react-router-dom URL遷移 • Font awesome アイコンライブラリ 5 Skip可:前回と同じスライド
ソースコード • 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可:前回と同じスライド
Reactとは(ダイジェスト) 7
Reactを使うアプリケーションの構成 https://ja.reactjs.org/ 8 • Reactは、Viewを提供するライブラリであり、それ以外の技術スタックを 組み合わせて使うことが前提 以下のような組み合わせで使う • Redux …
アプリケーションの状態管理フレームワークを使用したり、 • Redux-Saga … 非同期処理を扱うライブラリを使ったり、 • Back-end サーバー(RESTやSOAPサーバー)と組み合わせて構成する ここを取り上げます
状態管理 - Redux 9
Reduxとは? • Reactアプリケーションを補うライブラリで、 • アプリケーション全体の状態を管理し、 • ある一定のルールに沿った実装をすることで、 • ReactアプリケーションでのUI上のイベントと、 •
それに伴う状態の変化をUI上に自動で 更新させるアーキテクチャを提供する。 (Fluxアーキテクチャと呼ばれる) 10 https://redux.js.org/
Fluxアーキテクチャ • MVVMの双方向バインディ ングなどと異なり、ビューモ デルが「単一方向」で更新 されるアーキテクチャ • 右はイメージ(gif) • View(コンポーネント)と
Reducers(状態遷移)を 実装すればアプリの 画面が更新される 11 http://slides.com/jenyaterpil/redux-from-twitter-hype-to-production#/27
Reduxの構成要素 • 基本的に以下の5つから構成される 1. Store (State) 2. View (Component) 3.
Actions & Action Creator 4. Container (Dispatcher) 5. Reducers • MiddlewareはRedux-sagaなどが あり、非同期APIを呼ぶ場合もある 12 1 2 3 4 5
アプリケーションの状態とは? 13 • 例えば以下のような状態すべてを 含みます • ログインユーザーの情報 • ボードの一覧 •
ユーザーの一覧 • ボードごとのタスク一覧 • エラー情報 ログイン情報 ボード一覧 ボードごとの タスク一覧 ユーザー一覧 エラー情報
アプリケーションの状態とは? 14 ユーザー一覧 ボード一覧 エラー情報
Redux – Store (state) • アプリケーション全体の状態を表す • combineReducers を使って小さな 状態の集まりに粒度化できる
15 const appState = combineReducers({ loginState, mainState, boardsState, tasksState, usersState, errorState, }) export default appState const initialState = { boardIdToTasks: {}, isSavingNewTask: false, isSavingTask: false, boardIdToMoving: {} } tasksState.js const initialState = { users: [], isLoadingUsers: false, } usersState.js const store = createStore( appState, applyMiddleware(sagaMiddleware) ) sagaMiddleware.run(rootSaga) render( <Provider store={store}> <App /> </Provider>, document.getElementById("root") ) index.js reducers/index.js アプリケーション コンポーネント Store ボードごとの タスク一覧 ユーザー一覧 ・ ・ ・ ・ ・ ・ ・ ・ ・
Redux – View (Component)の役割 • コンポーネントはJSXで書かれる • 親から渡される読み取り専用の 状態 props
と、自身で書き込み 可能な状態 state を持つ • 画面のコントロール(ボタンや セレクトボックス)のイベントで、 それらの状態を変える関数を 呼び出す 16 TaskFrom コンポーネント UserFrom コンポーネント TaskCard コンポーネント Avatar コンポーネント Avatar コンポーネント
Redux – View (Component)の役割 17 UserFrom コンポーネント class UserForm extends
Component { constructor(props) { super(props) const user = props.user this.state = { name: user.name, password: user.password, avatar: user.avatar, } this.handleTextChange = this.handleTextChange.bind(this) this.handleAvatarChange = this.handleAvatarChange.bind(this) } 親から渡された props の user 画面が持つstate name password avatar の3フィールド stateを変える 関数
Redux – View(Component)の役割 18 <Col span={8}> {I18n.get("アカウント")}: </Col> <Col span={16}>
<Input autoFocus={true} value={this.state.name} onChange={(e) => this.handleTextChange(e, "name")} /> </Col> // snip handleTextChange(e, key) { this.setState({ [key]: e.target.value }) } onChange イベントハンドラ 入力値が変わったら setState関数で値を更新 onChange イベントハンドラ • stateは、setState関数で 更新する
Redux – View(Component)の役割 19 <Button type="primary" onClick={ () => {
const user = new User( this.props.user.id, this.state.name, this.state.avatar, this.props.user.version, ) user.newPassword = this.state.password this.props.onSaveButtonClick(user) } } disabled={disabled} loading={this.props.isSavingProcessing} style={{ float: "right" }} > {(!this.props.isSavingProcessing) ? I18n.get("保存") : I18n.get("保存中") } </Button> onClick イベントハンドラ onClick イベントハンドラ 画面が持つstateから、 Userインスタンスを作成 親から渡されたprops のコールバック関数を 呼び出し • propsは、親のコールバック 関数で更新する
Redux – Action / Action Creator • Action • UIやAPI呼び出しなどのイベント定義変数
• Action Creator • typeとpayloadと呼ばれるパラメータを持つ関数 20 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 updateLoginUserStartEvent = (user) => ({ type: UPDATE_LOGIN_USER_START_EVENT, payload: { user: user, } }) 保存ボタンのonClick イベントハンドラで 呼び出す UserFormで生成した Userインスタンスが 渡される
Redux – Container • コンポーネントと状態、Action の関数を接続させる役割を持 つ • mapStateToPropsでStoreの stateの一部とマッピングし、
mapDispatchToPropsでAction イベント関数をdispatchする • mapStateToPropsと mapDispatchToPropsを connect関数で接続する 21 import { connect } from "react-redux" import { withRouter } from "react-router-dom" import MenuBarPage from "../components/pages/MenuBarPage" import { updateLoginUserStartEvent, logoutStartEvent, switchMainViewEvent, } from "../actions" const mapStateToProps = (state) => ({ loginState: state.loginState, }) const mapDispatchToProps = (dispatch) => ({ switchMainViewIconClick: (view) => { dispatch(switchMainViewEvent(view)) }, onUserProfileSaveButtonClick: (user) => { dispatch(updateLoginUserStartEvent(user)) }, onLogoutIconClick: () => { dispatch(logoutStartEvent()) }, }) const MenuBarContainer = connect( mapStateToProps, mapDispatchToProps, )(MenuBarPage) export default withRouter(MenuBarContainer) アプリケーション全 体の状態の一部と マップ 画面からのcallback関数で、 Actionをdispatch(送出)する
Redux –Reducers • ロジックを司る関数 • 古い状態から新しい状態を作成する • Actionのtypeとpayloadによって状態を変える 22 const
loginState = (state = initialState, action) => { const type = action.type const payload = action.payload switch (type) { // snip case UPDATE_LOGIN_USER_START_EVENT: return { ...state, isSaveUserProcessing: true } case UPDATE_LOGIN_USER_SUCCESS_EVENT: return { ...state, isSaveUserProcessing: false, loginUser: payload.user } case UPDATE_LOGIN_USER_FAILURE_EVENT: return { ...state, isSaveUserProcessing: false } // snip } } 編集したUserとログイン ユーザーを差し替える
Reduxを使った開発でのフォルダ構成 23
Reduxのフォルダ構成 • 大きく分けて、2通りのやり方がある • Function-First : actions, components, containers, reducers
と機能単位で構成するやり方 規模が小さい場合に分かりやすい • Feature-First : ドメインや画面、データ単位で構成するやり方 ボリューム増でスケールする 24 https://www.freecodecamp.org/news/scaling-your-redux-app-with-ducks-6115955638be/
サンプルアプリケーションのフォルダ構成 • Function-Firstで作成 25
Componentのフォルダ構成 – Atomic Design • Atomic Design というコンポーネントの分類手法がある • コンポーネントを以下の5種に分類する
• Atoms … 原子:これ以上分割できない最小単位のコンポーネント • Molecules … 分子:原子が組み合わさったもの • Organisms … 組織:分子や原子の組み合わせで画面を構成するもの • Templates … テンプレート:ページの雛形 • Pages … ページ:最上位のコンポーネント。コンテナはページとだけ結合する 26
Componentのフォルダ構成 – Atomic Design • ContainersはPagesとだけ結合させ、画面コントロールのイベントのコールバックは Atoms まで引き回して実行させる • こうすることで、イベントとコンポーネントの独立性を高め、Organisms以下を再利用しやすくできる
27 class MenuBarPage extends Component { render() { return ( <MenuBarPageTemplate {...this.props} /> ) } } class MenuBarPageTemplate extends Component { render() { return ( <MenuBar {...this.props} /> ) } } const mapStateToProps = (state) => ({ loginState: state.loginState, }) const mapDispatchToProps = (dispatch) => ({ switchMainViewIconClick: (view) => { dispatch(switchMainViewEvent(view)) }, onUserProfileSaveButtonClick: (user) => { dispatch(updateLoginUserStartEvent(user)) }, onLogoutIconClick: () => { dispatch(logoutStartEvent()) }, }) const MenuBarContainer = connect( mapStateToProps, mapDispatchToProps, )(MenuBarPage) export default withRouter(MenuBarContainer) MenuBarPage.jsx MenuBarPageTemplate.jsx MenuBarContainer.js MenuBar.jsx Icon Avatar Icon MenuBarContainerから、 MenuBarPageを接続し、 MenuBarPageTemplate、 MenuBar、Iconへとprops を伝播させている Iconのクリックイベントは、 MenuBarContainerの コールバックを呼び出す Callback
サンプルアプリケーションのコンポーネント構成 以下の理由により4種にまとめた • Ant Designというコンポーネントライブラリを使用するため、 Atoms はほとんど作成しない • Atoms と
Molecules を basics という名前でまとめた • OrganismsとMoleculesの分類があいまいになるため、画 面のパーツ(ダイアログやフォーム)として再利用可能なも のを parts という名前にした 28 4種に分類 コンテナは Page単位で 作成
覚えていてほしいこと • Redux … アプリケーションの状態管理のReactのためのライブラリ • Store … アプリケーション全体の状態。細分化可能 •
Component … 画面コンポーネント。状態を持つ • Action … 画面イベントで送出されるパラメータ • Container … 画面と状態、イベントのマッピングをする • Reducers … 状態遷移のロジックを記述する • Function-FirstとFeature-Firstというフォルダ構成の取り方があること • Atomic Designというコンポーネントの階層化手法があること 29