てくてくあるく

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

Main Content

今回は Hello World と 表示されている 本文部分に 記事を 表示させていきたいと思います

前回の記事

React を 触ってみた (7) – 再帰処理 で全ての Taxonomy を 取得する
https://tekuaru.jack-russell.jp/2018/05/03/1810/

投稿 や 投稿一覧 を Material-UI の Card で 表示


タクソノミーの表示 と 流れは一緒なので
今回は サクッと Material-UI の Card を 使って 表示させていきたいと思います


/src/component-parts/card-posts.jsx


import React from 'react'

import { Link } from 'react-router-dom'

import PropTypes from 'prop-types'

import { withStyles } from 'material-ui/styles'

import Button from 'material-ui/Button'
import Card, { CardActions, CardContent } from 'material-ui/Card'

import Typography from 'material-ui/Typography'

import { connect } from 'react-redux'

import { mapStateToProps, mapDispatchToProps } from '../redux/containers'

const styles = {
  card: {
    marginBottom: 20,
  },
}

class CardPosts extends React.Component {
  constructor (props) {
    super(props)
  }

  componentWillMount() {
    console.log( 'componentWillMount' )
    this.props.handleLoadPosts( this.props )
  }

  componentWillReceiveProps(nextProps) {
    if(nextProps.location !== this.props.location) {
      console.log( 'componentWillReceiveProps' )
      this.props.handleLoadPosts( nextProps )
    }
  }

  render() {
    const { classes, posts } = this.props

    var card = ''
    if( Object.prototype.toString.call(this.props.posts) != '[object Array]' ) {
      var item = this.props.posts
      card = (
        <section>
          <Card className={classes.card}>
            <CardContent>
              <Typography variant="headline" component="h2">
                {item.title.rendered}
              </Typography>
              <Typography component="div" dangerouslySetInnerHTML={{__html: item.content.rendered}} />
            </CardContent>
          </Card>
        </section>
      )
    } else {
      card = (
        <section>
          {this.props.posts.map((item) => {
            return (
              <Card key={item.id} className={classes.card}>
                <CardContent>
                  <Typography variant="headline" component="h2">
                    {item.title.rendered}
                  </Typography>
                </CardContent>
                <CardActions>
                  <Button size="small" component={Link} to={`/posts/${item.id}`}>Learn More</Button>
                </CardActions>
              </Card>
            )
          })}
        </section>
      )
    }

    return card
  }
}

CardPosts.propTypes = {
  classes: PropTypes.object.isRequired,
}

export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(CardPosts))

render 内で 投稿用の表示と 投稿一覧用の表示を 分けていますが
本当なら ここも コンポーネントの読み出し時に 分けるのが良いのでしょうが 今回は 一緒にしています


/src/component/main.jsx : 一部


import { Switch, Route } from 'react-router-dom'

import CardPosts from '../component-parts/card-posts'

Switch, Route と CardPosts を 新たに 読み込みます


<h1>Hello World</h1>

と 書いていたコード は

<Switch>
  <Route exact path="/" component={CardPosts} />
  <Route exact path="/:taxonomy/:id/" component={CardPosts} />
  <Route exact path="/:taxonomy/:id/:page/" component={CardPosts} />
</Switch>

に 変更します

ココのポイントは Switch や exact で 条件を満たす者だけの コンポーネントを 選択している所です


Redux 関連


ここは そろそろ 感覚的に掴んできたのではないかと思いますので かなり ざっくりと コードを 載せていきます


/src/redux/containers.jsx : 一部


import { toggleDrawer, loadPosts, loadTaxonomies } from './actions'

export function mapDispatchToProps(dispatch) {
  return {
    /* 以前の記述 */
    handleLoadPosts: (props) => { dispatch( loadPosts(props) ) },
  }
}

/src/redux/actions.jsx : 一部


export function loadPosts(props, page = 1) {
  return function(dispatch) {
    var url = props.API.default + props.API.namespace
    if( Object.keys(props.match.params).length !== 0 ) {
      switch(props.match.params.taxonomy) {
        case 'posts':
          url += 'posts' + '/' + props.match.params.id + '/'
          break
        case 'pages':
          url += 'pages' + '/' + props.match.params.id + '/'
          break
        default:
          url += 'posts' + '/' + '?' + props.match.params.taxonomy + '=' + props.match.params.id
      }
    } else {
      url += 'posts' + '/'
    }

    fetch(url)
      .then(response => response.json())
      .then(result => dispatch(setPosts(result, props.match.params.taxonomy, page)))
      .catch(error => console.log(error))
    // end fetch
  }
}

export function setPosts(result, taxonomy = 'posts', page) {
  return {
    type: 'SET-POSTS',
    result,
    taxonomy,
    page,
  }
}

/src/redux/reducers.jsx : case のみ


const initialState = {
  /* 以前の記述 */
  posts: [],
}

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,
      })

    case 'SET-POSTS':
      console.log( action.taxonomy + ' : Page : ' + action.page )
      console.log( action.result )
      return Object.assign({}, state, {
        posts: action.result,
      })

    case 'SET-TAXONOMIES':
      console.log( action.taxonomy + ' : Page : ' + action.page )
      console.log( action.result )
      return Object.assign({}, state, {
        [action.taxonomy]: ( action.page == 1 ) ? action.result : state[action.taxonomy].concat(action.result),
      })

    default:
      return state
  }
}

という感じで 処理を 追記します

ココらへんは 前回の記事 を 参考に ちょっと 修正をすれば良い感じですかね


まとめ


今回のポイントは Route の path です

補足で 説明していませんでしたが :hoge とか :huga と書くと props.match.params 内に その変数が 格納されます

この格納されている 変数をもとに 自分が どこにいるのかの 判断になります

随分雑な記事になってしまいましたが わからないところ 不明なところがありましたら コメントお願いします

いつの間にか Bootstrap 4 が スタンバってるね!!

詳細へ »

Theme Customization API て 意外と簡単だった!!

詳細へ »