こんにちは、KOUKIです。Reactで画面開発を行なっています。
前回は、ログイン認証とログアウトを実装しました。今回は、ユーザー一覧を実装したいと思います。
尚、「React, NextJS and Golang: A Rapid Guide – Advanced」コースを参考にしています。解釈は私が勝手に付けているので、本物をみたい場合は受講をお勧めします!
<目次>
前回
事前準備
フォルダ/ファイル
1 |
touch react-admin/src/components/RedirectToUsers.tsx |
モジュール
1 2 |
cd react-admin/ npm install @material-ui/core |
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 |
// package.json { "name": "react-admin", "version": "0.1.0", "private": true, "dependencies": { "@material-ui/core": "^4.11.4", "@testing-library/jest-dom": "^5.11.4", "@testing-library/react": "^11.1.0", "@testing-library/user-event": "^12.1.10", "@types/jest": "^26.0.15", "@types/node": "^12.0.0", "@types/react": "^17.0.0", "@types/react-dom": "^17.0.0", "axios": "^0.21.1", "react": "^17.0.2", "react-dom": "^17.0.2", "react-router-dom": "^5.2.0", "react-scripts": "4.0.3", "typescript": "^4.1.2", "web-vitals": "^1.0.1" }, "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" }, "eslintConfig": { "extends": [ "react-app", "react-app/jest" ] }, "browserslist": { "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] }, "devDependencies": { "@types/react-router-dom": "^5.1.7" } } |
ユーザー一覧の作成
「http://localhost:8000/api/admin/ambassadors」へリクエストを飛ばすと、ユーザー一覧が取得できます。
※API開発編で実装しました
この機能を利用して、ユーザー一覧を表示する画面を作成しましょう。
ユーザー情報の取得
Users.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 |
// pages/Users.tsx import { useEffect, useState } from 'react' import { UserProps } from '../models/user' import Layout from '../components/Layout' import axios from 'axios' const Users = () => { // 状態管理 const [users, setUsers] = useState<UserProps[]>([]) let ambassadorsUrl = 'ambassadors' useEffect(() => { ( async () => { const { data } = await axios.get(ambassadorsUrl) setUsers(data) } )() }, [])// 第二引数は第一引数に指定した関数の実行タイミングを決める // 空を渡した場合、マウント・アンマウント時のみ第1引数の関数を実行 return ( <Layout> ... </Layout> ) } export default Users |
実装の流れとしては、以下のような感じです。
- userStateで、ユーザーの状態を管理する機能を設定する
- useEffectで、ページが表示・リダイレクトされたタイミングでユーザー情報を取得する
- axiosでユーザー情報を取得する
- setUserで、ユーザー情報をReactアプリに格納 -> users変数からいつでも取り出し可能になる
一覧を作成する
User.tsxのLayoutの中身を実装します。
先ほど、ユーザー情報をusers変数に配列形式でセットしたので、これを使ってユーザー一覧を作成します。
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 |
// pages/Users.tsx .... const Users = () => { ... return ( <Layout> <table className="table table-striped table-sm"> <thead> <tr> <th>#</th> <th>Name</th> <th>Name</th> <th>Actions</th> </tr> </thead> <tbody> {users.map(user => { return ( <tr key={user.id}> <td>{user.id}</td> <td>{user.first_name} {user.last_name}</td> <td>{user.email}</td> <td></td> </tr> ) })} </tbody> </table> </Layout> ) } ... |
リダイレクトコンポーネントの作成
ユーザーページは、「http://localhost:3000」および「http://localhost:3000/users」にアクセスした時に表示されるようにしたいと思います。
そこで、前者にアクセスした時は、後者へリダイレクトするためのコンポーネントを作成しましょう。
1 2 3 4 |
// components/RedirectToUsers.tsx import { Redirect } from 'react-router-dom' export const RedirectToUsers = () => <Redirect to={'/users'}></Redirect> |
ルーティングの設定
続いて、ルーティングの設定をします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
// App.tsx ... import {RedirectToUsers} from './components/RedirectToUsers' ... function App() { return ( <div className="App"> <BrowserRouter> <Route path={'/'} exact component={RedirectToUsers}></Route> // 修正 <Route path={'/users'} component={Users}></Route> // 追加 ... </BrowserRouter> </div> ); } export default App; |
Menuの変更
Menuの変更もしておきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
// src/components/Menu.tsx import { NavLink } from "react-router-dom" const Menu = () => { return ( <nav id="sidebarMenu" className="col-md-3 col-lg-2 d-md-block bg-light sidebar collapse"> <div className="position-sticky pt-3"> <ul className="nav flex-column"> <li className="nav-item"> <NavLink to={'/users'} className="nav-link" aria-current="page"> <span data-feather="home">Users</span> </NavLink> </li> </ul> </div> </nav> ) } export default Menu |
変更点は、以下です。
- Dashboard -> Usersに変更
- aタグ -> NavLinkに変更
画面表示
「http://localhost:3000」にアクセスして、画面を表示してみましょう。
Dockerが起動していない場合は、下記のコマンドで起動してください。
1 |
docker-compose up |

一覧が表示されれば、OKです。
ユーザー情報を登録していない場合は、以下の記事を参考にしてください。
Material-UIの導入
Material-UIを導入しましょう。
フォントリンクの追加
Material-UIでは、Robotoフォントが推奨されているようなので、publicフォルダにあるindex.htmlにリンクを追加します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<!-- public/index.html --> <!DOCTYPE html> <html lang="en"> <head> ... <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" /> <title>React App</title> </head> <body> ... </body> </html> |
ユーザー一覧の変更
Table Componentを参考に、先ほど実装したユーザー一覧を書き換えましょう。
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 |
// pages/Users.tsx ... import { Table, TableBody, TableRow, TableHead, TableCell } from '@material-ui/core' .... const Users = () => { ... return ( <Layout> <Table className="table table-striped table-sm"> <TableHead> <TableRow> <TableCell>#</TableCell> <TableCell>Name</TableCell> <TableCell>Name</TableCell> <TableCell>Actions</TableCell> </TableRow> </TableHead> <TableBody> {users.map(user => { return ( <TableRow key={user.id}> <TableCell>{user.id}</TableCell> <TableCell>{user.first_name} {user.last_name}</TableCell> <TableCell>{user.email}</TableCell> <TableCell></TableCell> </TableRow> ) })} </TableBody> </Table> </Layout> ) } export default Users |
paginationの実装
Material-UIには、Paginationも提供されています。
本アプリにも実装しましょう。
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 |
// pages/Users.tsx ... import { Table, TableBody, TableRow, TableHead, TableCell, TableFooter, TablePagination } from '@material-ui/core' ... const Users = () => { ... // ページ情報のState const [page, setPage] = useState(0) const perPage = 10 ... return ( <Layout> <Table className="table table-striped table-sm"> <TableHead> <TableRow>...</TableRow> </TableHead> <TableBody> {/* perPageごとにユーザーをスライス */} {users.slice(page * perPage, (page + 1) * perPage).map(user => { return ( <TableRow key={user.id}> ... </TableRow> ) })} </TableBody> <TableFooter> <TablePagination count={users.length} page={page} onChangePage={(e, newPage) => setPage(newPage)} rowsPerPageOptions={[]} rowsPerPage={perPage} ></TablePagination> </TableFooter> </Table> </Layout> ) } export default Users |
Paginationを実装するために、以下のことを行いました。
- useStateで、Pageの状態管理用の変数を用意
- テーブル作成時、sliceメソッドを使ってユーザーをページごとに分離
- TablePaginationでPaginationを作成
結構、簡単に実装できますね。
次回
次回は、Linkページを実装をしましょう。
Reactまとめ
参考書籍
ソースコード
ここまで実装したソースコードを下記に記載します。
Menu.tsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// src/components/Menu.tsx import { NavLink } from "react-router-dom" const Menu = () => { return ( <nav id="sidebarMenu" className="col-md-3 col-lg-2 d-md-block bg-light sidebar collapse"> <div className="position-sticky pt-3"> <ul className="nav flex-column"> <li className="nav-item"> <NavLink to={'/users'} className="nav-link" aria-current="page"> <span data-feather="home">Users</span> </NavLink> </li> </ul> </div> </nav> ) } export default Menu |
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 |
// App.tsx import './App.css'; import {BrowserRouter, Route} from 'react-router-dom' import {RedirectToUsers} from './components/RedirectToUsers' import Users from './pages/Users' import Login from './pages/Login' import Register from './pages/Register' function App() { return ( <div className="App"> <BrowserRouter> <Route path={'/'} exact component={RedirectToUsers}></Route> <Route path={'/users'} component={Users}></Route> <Route path={'/login'} component={Login}></Route> <Route path={'/register'} component={Register}></Route> </BrowserRouter> </div> ); } export default App; |
Users.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 65 66 67 68 69 70 71 72 |
// pages/Users.tsx import { useEffect, useState } from 'react' import { UserProps } from '../models/user' import { Table, TableBody, TableRow, TableHead, TableCell, TableFooter, TablePagination } from '@material-ui/core' import Layout from '../components/Layout' import axios from 'axios' const Users = () => { const [users, setUsers] = useState<UserProps[]>([]) // ページ情報のState const [page, setPage] = useState(0) const perPage = 10 let ambassadorsUrl = 'ambassadors' useEffect(() => { ( async () => { const { data } = await axios.get(ambassadorsUrl) setUsers(data) } )() }, []) return ( <Layout> <Table className="table table-striped table-sm"> <TableHead> <TableRow> <TableCell>#</TableCell> <TableCell>Name</TableCell> <TableCell>Name</TableCell> <TableCell>Actions</TableCell> </TableRow> </TableHead> <TableBody> {/* perPageごとにユーザーをスライス */} {users.slice(page * perPage, (page + 1) * perPage).map(user => { return ( <TableRow key={user.id}> <TableCell>{user.id}</TableCell> <TableCell>{user.first_name} {user.last_name}</TableCell> <TableCell>{user.email}</TableCell> <TableCell></TableCell> </TableRow> ) })} </TableBody> <TableFooter> <TablePagination count={users.length} page={page} onChangePage={(e, newPage) => setPage(newPage)} rowsPerPageOptions={[]} rowsPerPage={perPage} ></TablePagination> </TableFooter> </Table> </Layout> ) } export default Users |
RedirectToUsers.tsx
1 2 3 4 |
// components/RedirectToUsers.tsx import { Redirect } from 'react-router-dom' export const RedirectToUsers = () => <Redirect to={'/users'}></Redirect> |
index.html
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 |
<!-- public/index.html --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="theme-color" content="#000000" /> <meta name="description" content="Web site created using create-react-app" /> <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> <link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous"> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" /> <title>React App</title> </head> <body> <noscript>You need to enable JavaScript to run this app.</noscript> <div id="root"></div> </body> </html> |
コメントを残す
コメントを投稿するにはログインしてください。