React を 触ってみた (4) – Redux
今回は Redux を 使って 状態管理を していきます
前回の記事
React を 触ってみた (3) – Material-UI
https://tekuaru.jack-russell.jp/2018/04/30/1734/
この部分が非常に難しいので 今回は 前回実装した Drawer の 開閉の状態を 管理していきたいと思います
Redux とは
Redux は 全体を まとめて 状態管理してくれるもの という程度の理解しかないのです…
Redux入門【ダイジェスト版】10分で理解するReduxの基礎 - Qiitaを参考にさせていただきました。
https://qiita.com/kiita312/items/49a1f03445b19cf407b7
こちらが わかりやすいのかなって思いました
それでも 理解できないところがあるので これからの実装の部分 間違っているところが 多々あるかもしれません…
(参考程度にして 鵜呑みにしないようにお願いします)
Redux の インストール
(Dir : /var/www/html/)
今回も 作成に必要な パッケージを インストールします
npm install --save-dev redux react-redux
各々のバージョンは 以下のようになりました
"redux": "^4.0.0", "react-redux": "^5.0.7",
ファイル作成
わかりやすいように src 以下に redux ディレクトリを 作成します
/var/www/html/
-> src
-> redux
その中に
actions.jsx
containers.jsx
reducers.jsx
の ファイルを 作成します
データの流れ
初期値は reducers.jsx が 持っていて
/src/component/main.jsx 内にある
handleToggleDrawer() { this.setState({ mobileOpen: !this.state.mobileOpen }) }
の 部分が containers.jsx -> actions.jsx -> reducers.jsx それぞれに振り分けられるというイメージです
これだけだと 何を言っているのかわからないと思うので 一度ソースを 見てもらいます
/src/redux/containers.jsx
import React from 'react' import { connect } from 'react-redux' import Main from '../component/main' import { toggleDrawer } from './actions' function mapStateToProps(state) { return state } function mapDispatchToProps(dispatch) { return { handleToggleDrawer: () => { dispatch( toggleDrawer() ) }, } } export default connect(mapStateToProps, mapDispatchToProps)(Main)
/src/redux/actions.jsx
export function toggleDrawer() { return { type: 'TOGGLE-DRAWER', } }
/src/redux/reducers.jsx
const initialState = { mobileOpen: false, } export default function reducer(state = initialState, action) { switch(action.type) { case 'TOGGLE-DRAWER': console.log( 'mobileOpen : ' + !state.mobileOpen ) return Object.assign({}, state, { mobileOpen: !state.mobileOpen, }) default: return state } }
ソースを 見たら containers.jsx -> actions.jsx -> reducers.jsx の 意味が 何となく分かるかと思います
handleToggleDrawer -> toggleDrawer() -> TOGGLE-DRAWER -> return Object.assign({}, state, { mobileOpen: !state.mobileOpen, }) な 感じで 流れているのかなぁ… 程度で 今はいます
React と Redux を 連携させる
今度は 今まで作った React 側と 今作った Redux 側を 連携させます
/src/index.jsx
import React from 'react' import ReactDOM from 'react-dom' import { createStore } from 'redux' import { Provider } from 'react-redux' import Containers from './redux/containers' import Reducers from './redux/reducers' const store = createStore(Reducers) ReactDOM.render( <Provider store={store}> <Containers /> </Provider>, document.getElementById('root') )
こちらは ほぼほぼ内容が変わっています
今までは 直接 Main の コンポーネント を 表示させていたのですが 今回の変更で Containers を 通るようになっています
Containers から Main の コンポーネント を 表示 しています
/src/component/main.jsx : classのみ
class Main extends React.Component { constructor (props) { super(props) } render() { const { classes, theme } = this.props const drawer = ( <div> <List> <ListSubheader className={classes.drawerListSubheader} component="div">First List</ListSubheader> <ListItem button> <ListItemText primary="First List Button" /> </ListItem> </List> <Divider /> <List> <ListSubheader className={classes.drawerListSubheader} component="div">Second List</ListSubheader> <ListItem button> <ListItemText primary="Second List Button" /> </ListItem> </List> </div> ) return ( <div className={classes.root}> <AppBar className={classes.appBar}> <Toolbar> <IconButton color="inherit" aria-label="open drawer" onClick={() => this.props.handleToggleDrawer()} className={classes.navIconHide} > <MenuIcon /> </IconButton> <Typography variant="title" color="inherit" noWrap> Title </Typography> </Toolbar> </AppBar> <Hidden mdUp> <Drawer variant="temporary" anchor={theme.direction === 'rtl' ? 'right' : 'left'} open={this.props.mobileOpen} onClose={() => this.props.handleToggleDrawer()} classes={{ paper: classes.drawerPaper, }} ModalProps={{ keepMounted: true, // Better open performance on mobile. }} > {drawer} </Drawer> </Hidden> <Hidden smDown implementation="css"> <Drawer variant="permanent" open classes={{ paper: classes.drawerPaper, }} > {drawer} </Drawer> </Hidden> <main className={classes.content}> <div className={classes.toolbar} /> <h1>Hello World</h1> </main> </div> ) } }
Redux 側で 初期値を持ってくれているので
class Main extends React.Component 直下の this.state = { mobileOpen: false, } は カットです
同様に handleToggleDrawer() { this.setState({ mobileOpen: !this.state.mobileOpen }) } も カットです
そして IconButton の onClick と Drawer の open と onClose の 読み出し先を this. から this.props. に 変更します
ページを確認
First React Project
http://react/
Reduxで 状態管理が されているか 確認してみましょう
( コンパイルを 忘れずにね )
メニューアイコン を 押して 開いたり 閉じたりしたあと
ブラウザの デベロッパーツール等で javaScript の コンソールログで 確認してみてください
mobileOpen : true
mobileOpen : false
みたいに 結果が表示されていれば Reduxで 状態管理されています
( reducers.jsx に console.log を 仕込んであれば ですが )
表示されていなかったり エラーが表示されていた場合 記述ミスや 記法の変更があったかもしれません
まとめ
Redux の 動作や 理念について 理解しきれていないので
React 以上に ふわっとした ニュアンスでしか 記事がかけていなくてすみません