こんにちは、mabuiです。
これまでの記事ではReactで仮想通貨の情報を表示するサンプルを
一つづつ技術を取り入れて作ってきましたが、
最後にMaterial-UIのコンポーネントを取り入れて、
デザインを良くしたものにして開発を終了しようと思います。
動作イメージ
導入した画面がこちらです。
これまでのものと比べると、ヘッダーがついたり、
ボタンがリッチになったり、テーブル構造になったりと
かなりそれっぽいものになったと思います。
Material-UIとは?
Material-UIは、Goggleが提供している
Reactのコンポーネントをまとめたライブラリです。
マテリアルデザインに従った、おしゃれなUIパーツを
使用することができます。
最初にMaterial-UI導入すれば良かった、、
今回ボタン、テーブル、ヘッダーバーをMaterial-UIのものに
差し替えましたが、コンポーネントには
テーブルにはソートの機能など、
実装に必要なロジックがあらかじめ用意されているため、
自前で用意した処理が大幅に不要になりました、、、
今後開発をする時はまず外部のコンポーネントを使用するかどうかを
決定させてから進めたほうが効率がいいと思いました。
コード紹介
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
import TitleAppBar from './title_app_bar'; import ChangeCurrency from './change_currency'; import CurrencyTable from './currency_table'; // コンポーネント作成 class ReduxTest extends React.Component { constructor(props) { super(props); props.setCoins(); } render() { const { list, display, changeDisplay, handleRequestSort, order, orderBy } = this.props; return ( <Fragment> <TitleAppBar title='Top 10 Cryptocurrencies By Market Capitalization'/> <ChangeCurrency display={display} changeDisplay={changeDisplay} /> <CurrencyTable list={list} display={display} handleRequestSort={handleRequestSort} order={order} orderBy={orderBy} /> </Fragment> ) } } export default ReduxTest |
こちらは通貨一覧画面のコンポーネントクラスです。
TitleAppBarがタイトルバー、
ChangeCurrencyが通貨切り替えボタン、
CurrencyTableがテーブルのそれぞれのコンポーネントになっていて、
画面をそれぞれのUIパーツの組み合わせで構築する、
Reactの考え方に沿ったものになっています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
import React from 'react'; import PropTypes from 'prop-types'; import Button from '@material-ui/core/Button'; import { withStyles } from '@material-ui/core/styles'; import Constants from "../constants"; const styles = theme => ({ button: { margin: theme.spacing.unit, }, }); class ChangeCurrency extends React.Component { render() { const { classes, display, changeDisplay } = this.props; return ( <div className={classes.root}> <Button variant="outlined" className={classes.button} onClick={() => changeDisplay(display)}> {display === Constants.DISPLAY_JPY ? Constants.DISPLAY_JPY : Constants.DISPLAY_USD} </Button> </div> ); } } ChangeCurrency.propTypes = { classes: PropTypes.object.isRequired, display: PropTypes.string.isRequired, }; export default withStyles(styles)(ChangeCurrency); |
こちらは通貨切り替えボタンのコンポーネント実装、
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
import React from 'react'; import PropTypes from 'prop-types'; import { withStyles } from '@material-ui/core/styles'; import Table from '@material-ui/core/Table'; import TableBody from '@material-ui/core/TableBody'; import TableCell from '@material-ui/core/TableCell'; import TableHead from '@material-ui/core/TableHead'; import TableRow from '@material-ui/core/TableRow'; import TableSortLabel from '@material-ui/core/TableSortLabel'; import Paper from '@material-ui/core/Paper'; import Tooltip from '@material-ui/core/Tooltip'; import Constants from "../constants"; import {Link} from "react-router-dom"; function getSorting(order, orderBy) { return order === 'desc' ? (a, b) => b[orderBy] - a[orderBy] : (a, b) => a[orderBy] - b[orderBy]; } const columnData = [ { id: 'name', numeric: false, disablePadding: false, label: 'name' }, { id: 'price', numeric: true, disablePadding: false, label: 'price' }, { id: 'market_cap', numeric: true, disablePadding: false, label: 'market cap' }, { id: 'percent_change_24h', numeric: true, disablePadding: false, label: 'percent change 24h' }, ]; class CurrencyTableHead extends React.Component { createSortHandler = property => event => { this.props.onRequestSort(event, property, this.props.order, this.props.orderBy); }; render() { const { order, orderBy, } = this.props; return ( <TableHead> <TableRow> {columnData.map(column => { return ( <TableCell key={column.id} numeric={column.numeric} padding={column.disablePadding ? 'none' : 'default'} sortDirection={orderBy === column.id ? order : false} > <Tooltip title="Sort" placement={column.numeric ? 'bottom-end' : 'bottom-start'} enterDelay={300} > <TableSortLabel active={orderBy === column.id} direction={order} onClick={this.createSortHandler(column.id)} > {column.label} </TableSortLabel> </Tooltip> </TableCell> ); }, this)} </TableRow> </TableHead> ); } } CurrencyTableHead.propTypes = { onRequestSort: PropTypes.func.isRequired, order: PropTypes.string.isRequired, orderBy: PropTypes.string.isRequired, }; const styles = theme => ({ root: { width: '100%', marginTop: theme.spacing.unit * 3, }, table: { minWidth: 1020, }, tableWrapper: { overflowX: 'auto', }, }); class CurrencyTable extends React.Component { render() { const { classes, list, display, handleRequestSort, order, orderBy } = this.props; return ( <Paper className={classes.root}> <div className={classes.tableWrapper}> <Table className={classes.table} aria-labelledby="tableTitle"> <CurrencyTableHead order={order} orderBy={orderBy} onRequestSort={handleRequestSort} /> <TableBody> {list .sort(getSorting(order, orderBy)) .map(coin => { // テーブルヘッダのidと合わせてソートできるようにするため、変数を追加 coin.price = display === Constants.DISPLAY_JPY ? coin.price_jpy : coin.price_usd; coin.market_cap = display === Constants.DISPLAY_JPY ? coin.market_cap_jpy : coin.market_cap_usd; return coin }) .map(coin => { return ( <TableRow hover> <TableCell><Link to={`/detail/${coin.website_slug}`}>{coin.name}</Link></TableCell> <TableCell numeric>{coin.price}</TableCell> <TableCell numeric>{coin.market_cap}</TableCell> <TableCell numeric>{coin.percent_change_24h}</TableCell> </TableRow> ); })} </TableBody> </Table> </div> </Paper> ); } } CurrencyTable.propTypes = { classes: PropTypes.object.isRequired, }; export default withStyles(styles)(CurrencyTable); |
こちらはテーブルのコンポーネント実装です。
実装したコードのgithubはこちらです。
サンプル作ってみて、振り返り
これまでサンプルを作る過程で、
React、Redux、redux-thunk、react-router-dom、Plotly.js、Material-UIの
理解を深めることができました。
フロントエンド側で非同期通信のapiコールを実装したことで、
サーバーサイドの実装なく動的なサンプルサービスを作ることができて、
JavaScriptでのサービス開発の理解も深まったと思います。
再利用性の高いパーツを組み合わせてサービスを作り上げていく、
Reactの考え方は個人的にも合理的で好きなので、
今後仕事での開発でも個人的なサービス開発でも活用していこうと思っています!