てくてくあるく

WordPress の テーマ とか プラグイン に ついて 勉強しています

今回は 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 以上に ふわっとした ニュアンスでしか 記事がかけていなくてすみません

Related Article

Gutenberg の カスタムブロック を 作ってみる (create-guten-block)

詳細へ »

React で 複数のスタイル を 指定する方法

詳細へ »