こんにちは、KOUKIです。Reactで画面開発を行なっています。
前回は、Linkページを実装しました。今回は、Productページの実装を行います。
尚、「React, NextJS and Golang: A Rapid Guide – Advanced」コースを参考にしています。解釈は私が勝手に付けているので、本物をみたい場合は受講をお勧めします!
<目次>
前回
事前準備
フォルダ/ファイル
1 2 3 |
mkdir react-admin/src/pages/products touch react-admin/src/pages/products/Products.tsx touch react-admin/src/models/Product.ts |
Productページ
早速、Productページを作成していきましょう。
Productモデル
まず、以下のモデルを作成します。
1 2 3 4 5 6 7 8 9 |
// models/Product.ts export interface Product { id: number title: string description: string image: string price: string } |
このモデルは、Productページで、データの型付けのために使います。
1 2 3 4 5 6 7 8 9 |
// pages/products/Products.tsx import { useState } from 'react' import { Product } from '../../models/Product' const Products = () => { const [products, setProduct] = useState<Product[]>([]) return (...) } export default Products |
Product取得処理
次に、axiosでProduct取得処理を実装します。
※処理は、これまで実装してきたものと同じなので、詳細は割愛します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
// pages/products/Products.tsx import { useState, useEffect } from 'react' import { Product } from '../../models/Product' import axios from 'axios' const Products = () => { const [products, setProducts] = useState<Product[]>([]) const productsUrl = '/products' useEffect(() => { ( async () => { const { data } = await axios.get(productsUrl) setProducts(data) } )() }, []) return (...) } export default Products |
ページの実装
Productのページを実装します。これは、前回実装したUserページとほぼ同じです。
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 |
// pages/products/Products.tsx ... import { Button, Table, TableBody, TableRow, TableHead, TableCell, TableFooter, TablePagination } from '@material-ui/core' import Layout from '../../components/Layout' const Products = () => { const [products, setProducts] = useState<Product[]>([]) const productsUrl = '/productss' const [page, setPage] = useState(0) const perPage = 10 useEffect(() => {...}) return ( <Layout> <Table className="table table-striped table-sm"> <TableHead> <TableRow> <TableCell>#</TableCell> <TableCell>Image</TableCell> <TableCell>Title</TableCell> <TableCell>Description</TableCell> <TableCell>Price</TableCell> <TableCell>Actions</TableCell> </TableRow> </TableHead> <TableBody> {products.slice(page * perPage, (page + 1) * perPage).map(product => { return ( <TableRow key={product.id}> <TableCell>{product.id}</TableCell> <TableCell><img src={product.image} width={50}/></TableCell> <TableCell>{product.title}</TableCell> <TableCell>{product.description}</TableCell> <TableCell>{product.price}</TableCell> <TableCell></TableCell> </TableRow> ) })} </TableBody> <TableFooter> <TableRow> <TablePagination count={products.length} page={page} onChangePage={(e, newPage) => setPage(newPage)} rowsPerPageOptions={[]} rowsPerPage={perPage} ></TablePagination> </TableRow> </TableFooter> </Table> </Layout> ) } export default Products |
Tableなどには、Material-UIを使っています。
Material-UIは、ページネーション機能も提供しているので、かなり便利です。
ルートの追加
Productページへのルートを追加しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// App.tsx ... import Products from './pages/products/Products' function App() { return ( <div className="App"> <BrowserRouter> ... <Route path={'/products'} component={Products}></Route> </BrowserRouter> </div> ); } export default App; |
これで、ブラウザから「http://localhost:3000/products」へアクセスしたらProductページへ遷移できるようになりました。
Menuの変更
MenuからProductページへ遷移できるようにしましょう。
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 |
// 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"> Users </NavLink> </li> <li className="nav-item"> <NavLink to={'/products'} className="nav-link" aria-current="page"> Products </NavLink> </li> </ul> </div> </nav> ) } export default Menu |
確認
ブラウザから「http://localhost:3000/products」へアクセスし、Productsページへアクセスできるか確認しましょう。

imageへのパスはダミーなので表示エラーになっていますが、これでOKです。
削除処理
Productsの「Actions」に削除ボタンをつけましょう。
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 |
// pages/products/Products.tsx .... const Products = () => { const [products, setProducts] = useState<Product[]>([]) ... const del = async (id: number) => { if (window.confirm('商品を削除しますか?')) { await axios.delete(`${productsUrl}/${id}`) setProducts(products.filter(p => p.id !== id)) } } return ( <Layout> <Table className="table table-striped table-sm"> <TableHead> ... </TableHead> <TableBody> {products.slice(page * perPage, (page + 1) * perPage).map(product => { return ( <TableRow key={product.id}> ... <TableCell> <Button variant="contained" color="secondary" onClick ={() => del(product.id)} >Delete</Button> </TableCell> </TableRow> ) })} </TableBody> ... </Table> </Layout> ) } export default Products |
Productを削除するAPIのエンドポイントは、「http://localhost:8000/api/admin/products/{product_id}」です。
問題なく削除されるか、確認しましょう。
Okですね。
次回
次回は、Productの作成機能を実装します。
Reactまとめ
参考書籍
ソースコード
ここまで実装したソースコードを下記に記載します。
Products.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 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
// pages/products/Products.tsx import { useState, useEffect } from 'react' import { Product } from '../../models/Product' import axios from 'axios' import { Button, Table, TableBody, TableRow, TableHead, TableCell, TableFooter, TablePagination } from '@material-ui/core' import Layout from '../../components/Layout' const Products = () => { const [products, setProducts] = useState<Product[]>([]) const productsUrl = '/products' const [page, setPage] = useState(0) const perPage = 10 useEffect(() => { ( async () => { const { data } = await axios.get(productsUrl) setProducts(data) } )() }, []) const del = async (id: number) => { if (window.confirm('商品を削除しますか?')) { await axios.delete(`${productsUrl}/${id}`) setProducts(products.filter(p => p.id !== id)) } } return ( <Layout> <Table className="table table-striped table-sm"> <TableHead> <TableRow> <TableCell>#</TableCell> <TableCell>Image</TableCell> <TableCell>Title</TableCell> <TableCell>Description</TableCell> <TableCell>Price</TableCell> <TableCell>Actions</TableCell> </TableRow> </TableHead> <TableBody> {products.slice(page * perPage, (page + 1) * perPage).map(product => { return ( <TableRow key={product.id}> <TableCell>{product.id}</TableCell> <TableCell><img src={product.image} width={50}/></TableCell> <TableCell>{product.title}</TableCell> <TableCell>{product.description}</TableCell> <TableCell>{product.price}</TableCell> <TableCell> <Button variant="contained" color="secondary" onClick ={() => del(product.id)} >Delete</Button> </TableCell> </TableRow> ) })} </TableBody> <TableFooter> <TableRow> <TablePagination count={products.length} page={page} onChangePage={(e, newPage) => setPage(newPage)} rowsPerPageOptions={[]} rowsPerPage={perPage} ></TablePagination> </TableRow> </TableFooter> </Table> </Layout> ) } export default Products |
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 25 26 |
// 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' import Links from './pages/Links' import Products from './pages/products/Products' function App() { return ( <div className="App"> <BrowserRouter> <Route path={'/'} exact component={RedirectToUsers}></Route> <Route path={'/login'} component={Login}></Route> <Route path={'/register'} component={Register}></Route> <Route path={'/users'} exact component={Users}></Route> <Route path={'/users/:id/links'} component={Links}></Route> <Route path={'/products'} component={Products}></Route> </BrowserRouter> </div> ); } export default App; |
Menu.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 |
// 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"> Users </NavLink> </li> <li className="nav-item"> <NavLink to={'/products'} className="nav-link" aria-current="page"> Products </NavLink> </li> </ul> </div> </nav> ) } export default Menu |
Product.tx
1 2 3 4 5 6 7 8 9 |
// models/Product.ts export interface Product { id: number title: string description: string image: string price: string } |
コメントを残す
コメントを投稿するにはログインしてください。