こんにちは、KOUKIです。
Reactで画面開発をハンズオン形式で紹介しています。
今回は、StatsとRankingの実装をします。
尚、「React, NextJS and Golang: A Rapid Guide – Advanced」コースを参考にしています。解釈は私が勝手に付けているので、本物をみたい場合は受講をお勧めします!
<目次>
前回
前回は、ヘッダーコンポーネントの実装を行いました。
事前準備
ファイル
1 2 |
touch react-ambassador/src/pages/Stats.tsx touch react-ambassador/src/pages/Rankings.tsx |
Stats
Stats APIは、以下の記事で作成しています。
ページの作成
ページの実装を行います。
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 |
// pages/Stats.tsx import { useEffect, useState } from "react" import Layout from '../components/Layout' import axios from 'axios' const Stats = () => { const statsUrl = 'stats' const [stats, setStats] = useState([]) useEffect(() => { ( async () => { const { data } = await axios.get(statsUrl) if (data) { setStats(data) } } )() }, []) return ( <Layout> <div className="table-responsive"> <table className="table table-striped table-sm"> <thead> <tr> <th>#</th> <th>Name</th> <th>Revenue</th> </tr> </thead> </table> </div> </Layout> ) } export default Stats |
tableのbodyは、この後実装します。
ルートの追加
Statsページのルートを追加iします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// App.tsx ... import Stats from './pages/Stats' function App() { return ( <BrowserRouter> ... <Route path={'/stats'} component={Stats} /> </BrowserRouter> ); } export default App; |
ナビゲーションへの追加
Statsページのリンクをナビゲーションに追加します。
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 |
// components/Nav.tsx ... const Nav = (props: any) => { ... if (props.user?.id) { menu = ( <div className="col-md-3 text-end"> <Link to={'/stats'} className="btn me-2">Stats</Link> // 追加 <Link to={'/profile'} className="btn btn-primary"> {props.user.first_name} {props.user.last_name} </Link> <a href="#" className="btn btn-outline-primary me-2" onClick={logout} > logout </a> </div> ) } else { ... } )(Nav) |
ページの表示
下記のコマンドで、dockerコンテナを立ち上げます。
1 |
docker-compose up |
ブラウザから「http://localhost:4000/stats」へアクセスしましょう。

Tableの作成
画面の表示が確認できたら、Tableを作成しましょう。
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 |
// pages/Stats.tsx ... const Stats = () => { ... return ( <Layout> <div className="table-responsive"> <table className="table table-striped table-sm"> <thead> ... </thead> <tbody> {stats.map((s: { code: string, revenue: number }, index) => { return ( <tr key={index}> <td>{`http://localhost:5000/${s.code}`}</td> <td>{s.code}</td> <td>{s.revenue}</td> </tr> )})} </tbody> </table> </div> </Layout> ) } export default Stats |
この記事を参考にStatsにデータを追加後、画面を表示してみましょう。

Ranking
次は、Raningの実装に入ります。
Rankings APIは、次の記事で実装しました。
ページの作成
Statsページとほぼ同じなので、サクッと作ってしまいます。
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 |
// pages/Rankings.tsx import { useEffect, useState } from "react" import Layout from '../components/Layout' import axios from 'axios' const Rankings = () => { const rankingsUrl = 'rankings' const [rankings, setRankings] = useState([]) useEffect(() => { ( async () => { const { data } = await axios.get(rankingsUrl) if (data) { setRankings(data) } } )() }, []) return ( <Layout> <div className="table-responsive"> <table className="table table-striped table-sm"> <thead> <tr> <th>#</th> <th>Name</th> <th>Revenue</th> </tr> </thead> <tbody> {Object.keys(rankings).map((key: any, index) => { return ( <tr key={key}> <td>{index + 1}</td> <td>{key}</td> <td>{rankings[key]}</td> </tr> ) })} </tbody> </table> </div> </Layout> ) } export default Rankings |
ルートの追加
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// App.tsx ... import Rankings from './pages/Rankings' function App() { return ( <BrowserRouter> ... <Route path={'/rankings'} component={Rankings} /> </BrowserRouter> ); } export default App; |
ナビゲーションの追加
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
// components/Nav.tsx ... const Nav = (props: any) => { .... if (props.user?.id) { menu = ( <div className="col-md-3 text-end"> <Link to={'/rankings'} className="btn me-2">Rankings</Link> // 追加 <Link to={'/stats'} className="btn me-2">Stats</Link> ... ) } else { ... } ... } .... |
データ投入
RankingデータはRedisに格納しているのですが、データが🈳になっている場合が考えられるので、以下のコマンドでデータを投入してください。
1 |
docker-compose run --rm backend sh -c "go run src/commands/redis/updateRankings.go" |
ページの表示
ブラウザから「http://localhost:4000/rankings」へアクセスして、ページを表示しましょう。

次回
次回は、Productsの実装をしましょう。
Reactまとめ
参考書籍
ソースコード
Stats.tsx
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 |
// pages/Stats.tsx import { useEffect, useState } from "react" import Layout from '../components/Layout' import axios from 'axios' const Stats = () => { const statsUrl = 'stats' const [stats, setStats] = useState([]) useEffect(() => { ( async () => { const { data } = await axios.get(statsUrl) if (data) { setStats(data) } } )() }, []) return ( <Layout> <div className="table-responsive"> <table className="table table-striped table-sm"> <thead> <tr> <th>#</th> <th>Name</th> <th>Revenue</th> </tr> </thead> <tbody> {stats.map((s: { code: string, revenue: number }, index) => { return ( <tr key={index}> <td>{`http://localhost:5000/${s.code}`}</td> <td>{s.code}</td> <td>{s.revenue}</td> </tr> )})} </tbody> </table> </div> </Layout> ) } export default Stats |
Rankings.tsx
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 |
// pages/Rankings.tsx import { useEffect, useState } from "react" import Layout from '../components/Layout' import axios from 'axios' const Rankings = () => { const rankingsUrl = 'rankings' const [rankings, setRankings] = useState([]) useEffect(() => { ( async () => { const { data } = await axios.get(rankingsUrl) if (data) { setRankings(data) } } )() }, []) return ( <Layout> <div className="table-responsive"> <table className="table table-striped table-sm"> <thead> <tr> <th>#</th> <th>Name</th> <th>Revenue</th> </tr> </thead> <tbody> {Object.keys(rankings).map((key: any, index) => { return ( <tr key={key}> <td>{index + 1}</td> <td>{key}</td> <td>{rankings[key]}</td> </tr> ) })} </tbody> </table> </div> </Layout> ) } export default Rankings |
App.tsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
// App.tsx import { BrowserRouter, Route } from 'react-router-dom' import ProductsFrontend from './pages/ProductsFrontend' import Login from './pages/Login' import Register from './pages/Register' import Profile from './pages/Profile' import Stats from './pages/Stats' import Rankings from './pages/Rankings' import './App.css'; function App() { return ( <BrowserRouter> <Route path={'/'} exact component={ProductsFrontend} /> <Route path={'/login'} component={Login} /> <Route path={'/register'} component={Register} /> <Route path={'/profile'} component={Profile} /> <Route path={'/stats'} component={Stats} /> <Route path={'/rankings'} component={Rankings} /> </BrowserRouter> ); } export default App; |
Nav.tsx
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 |
// components/Nav.tsx import { Dispatch } from 'react' import { connect } from 'react-redux' import { User } from '../models/user' import { Link } from 'react-router-dom' import axios from 'axios' import { setUserAction } from '../redux/actions/setUserAction' const Nav = (props: any) => { const logout = async () => { await axios.post('logout') props.setUser(null) } let menu if (props.user?.id) { menu = ( <div className="col-md-3 text-end"> <Link to={'/rankings'} className="btn me-2">Rankings</Link> <Link to={'/stats'} className="btn me-2">Stats</Link> <Link to={'/profile'} className="btn btn-primary"> {props.user.first_name} {props.user.last_name} </Link> <a href="#" className="btn btn-outline-primary me-2" onClick={logout} > logout </a> </div> ) } else { menu = ( <div className="col-md-3 text-end"> <Link to={'/login'} className="btn btn-outline-primary me-2">Login</Link> <Link to={'/register'} className="btn btn-primary">Sign-up</Link> </div> ) } return ( <div className="container"> <header className="d-flex flex-wrap align-items-center justify-content-center justify-content-md-between py-3 mb-4 border-bottom"> <ul className="nav col-12 col-md-auto mb-2 justify-content-center mb-md-0"> <li><a href="#" className="nav-link px-2 link-secondary">Frontend</a></li> <li><a href="#" className="nav-link px-2 link-dark">Backend</a></li> </ul> {menu} </header> </div> ) } export default connect( (state: {user: User}) => ({ user: state.user }), (dispatch: Dispatch<any>) => ({ setUser: (user: User) => dispatch(setUserAction(user)) }) )(Nav) |
コメントを残す
コメントを投稿するにはログインしてください。