React を 触ってみた (4) – Redux
今回は Redux を 使って 状態管理を していきます
前回の記事
React を 触ってみた (3) – Material-UI
https://tekuaru.jack-russell.jp/2018/04/30/1734/
この部分が非常に難しいので 今回は 前回実装した Drawer の 開閉の状態を 管理していきたいと思います
Redux とは
Redux は 全体を まとめて 状態管理してくれるもの という程度の理解しかないのです…
I referred to 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 以上に ふわっとした ニュアンスでしか 記事がかけていなくてすみません