はじめに
概要
この記事は、トラハック氏(@torahack_)が運営するYoutubeチャンネル『トラハックのエンジニア学習ゼミ【とらゼミ】』の『日本一わかりやすいReact-Redux講座 実践編』の学習備忘録です。
前回の講座で、ヘッダーのカートアイコンのバッチ数を、DB情報とリアルタイム同期させることができました。
今回は、カート商品の購入処理を実装する前段階として、カート詳細ページのビューファイルを作ります。
※ 前回記事: 【【備忘録】日本一わかりやすいReact-Redux講座 実践編 #11 「Firestoreでリアルタイムに表示を更新しよう」
動画URL
トランザクションを使って商品を注文しよう(前半)【日本一わかりやすいReact-Redux講座 実践編#12】
要点
- リスト表示を実装する際は、
map
メソッドでリストアイテム用コンポーネントをイテレートする。
完成系イメージ
ヘッダーのカートアイコンをクリックすると、カート情報ページ( path: http://localhost:3000/cart
)へ遷移します。
カートに入れた商品が表示されています。ゴミ箱アイコンを押すことで、カートから商品を削除できます。
メイン
**http://localhost:3000/cart
**に対して、カート情報ページを作成します。CartList.jsx
テンプレートに対してCartListItem.jsx
を子コンポーネントとして配置します。
UIKit
コンポーネントしてGreyBottun.jsx
も追加します。
ファイル実装
1.src/components/UIkit/GreyButton.jsx
2.src/components/UIkit/index.js
3.src/templates/CartList.jsx
4.src/templates/index.js
5.src/components/Products/CartListItem.jsx
6.src/components/Products/index.js
7.src/Router.jsx
import React from "react";
import Button from "@material-ui/core/Button";
import {makeStyles} from "@material-ui/styles";
const useStyles = makeStyles((theme) => ({
"button": {
backgroundColor: theme.palette.grey["300"],
fontSize: 16,
height: 48,
marginButton: 16,
width: 256
}
}))
const GreyButton = (props) => {
const classes = useStyles();
return(
<Button className={classes.button} variant="contained" onClick={() => props.onClick()}>
{props.label}
</Button>
)
}
export default GreyButton
export {default as GreyButton} from "./GreyButton"
export {default as PrimaryButton} from "./PrimaryButton"
export {default as SelectBox} from "./SelectBox"
export {default as TextInput} from "./TextInput"
PrimaryButton.jsx
の色を変えただけです。
import React, { useCallback } from "react";
import {useDispatch, useSelector} from "react-redux"
import List from "@material-ui/core/List"
import {makeStyles} from "@material-ui/core/styles";
import { getProductsInCart } from "../reducks/users/selectors";
import {CartListItem} from "../components/Products"
import {PrimaryButton, GreyButton} from "../components/UIkit"
import {push} from "connected-react-router"
const useStyles = makeStyles((theme) => ({
root: {
margin: '0 auto',
maxWidth: 512,
width: '100%'
},
}));
const CartList = () => {
const classes = useStyles();
const dispatch = useDispatch();
const selector = useSelector((state)=>state);
const productsInCart = getProductsInCart(selector);
const goToOrder = useCallback(() => {
dispatch(push("/order/confirm"))
},[])
const backToTop = useCallback(() => {
dispatch(push("/"))
},[])
return (
<section className="c-section-wrapin">
<h2 className="u-text__headline">ショッピングカート</h2>
<List className={classes.root}>
{productsInCart.length > 0 && (
productsInCart.map(product => <CartListItem product={product} key={product.cartId} />)
)}
</List>
<div className="module-spacer--medium" />
<div className="p-grid__column">
<PrimaryButton label={"レジへ進む"} onClick={goToOrder} />
<div className="module-spacer--extra-extra-small"/>
<GreyButton label={"ショッピングを続ける"} onClick={backToTop} />
</div>
</section>
)
}
export default CartList
map
メソッドで、リストアイテムの子コンポーネントを繰り返し描画するのは、もうお馴染みですね。
export {default as CartList} from './CartList' //追記
export {default as Home} from './Home'
export {default as ProductDetail} from './ProductDetail'
export {default as ProductEdit} from './ProductEdit'
export {default as ProductList} from './ProductList'
export {default as Reset} from './Reset'
export {default as SignIn} from './SignIn'
export {default as SignUp} from './SignUp'
import React from 'react';
import Divider from '@material-ui/core/Divider';
import ListItem from '@material-ui/core/ListItem';
import ListItemText from '@material-ui/core/ListItemText';
import ListItemAvatar from '@material-ui/core/ListItemAvatar';
import {makeStyles} from "@material-ui/styles";
import DeleteIcon from "@material-ui/icons/Delete";
import IconButton from "@material-ui/core/IconButton";
import {useSelector} from "react-redux";
import {getUserId} from "../../reducks/users/selectors";
import {db} from "../../firebase/index"
const useStyles = makeStyles((theme)=>({
list: {
height: 128,
},
image: {
objectFit: "cover",
margin: 16,
height: 96,
width: 96
},
text: {
width: "100%"
}
}));
const CartListItem = (props) => {
const classes = useStyles();
const selector = useSelector(state => state);
const uid = getUserId(selector)
const image = props.product.images[0].path;
const name = props.product.name
const price = props.product.price.toLocaleString();
const size = props.product.size
const removeProductFromCart = (id) => {
return db.collection("users").doc(uid)
.collection("cart").doc(id)
.delete()
}
return (
<>
<ListItem className={classes.list}>
<ListItemAvatar>
<img className={classes.image} src={image} alt="商品画像"/>
</ListItemAvatar>
<div className={classes.text}>
<ListItemText
primary={name}
secondary={"サイズ:" + size}
/>
<ListItemText
primary={"¥" + price}
/>
</div>
<IconButton onClick={() => removeProductFromCart(props.product.cartId)}>
<DeleteIcon/>
</IconButton>
</ListItem>
<Divider/>
</>
);
};
export default CartListItem
removeProductFromCart()
で、カートの追加した商品をDB上から削除できるようにしています。
export {default as CartListItem} from "./CartListItem" //追記
export {default as ImageArea} from "./ImageArea"
export {default as ImagePreview} from "./ImagePreview"
export {default as ImageSwiper} from "./ImageSwiper"
export {default as ProductCard} from "./ProductCard"
export {default as SetSizeArea} from "./SetSizeArea"
export {default as SizeTable} from "./SizeTable"
import React from 'react';
import {Route, Switch} from "react-router";
import {CartList, ProductDetail,ProductEdit,ProductList,Reset,SignIn,SignUp} from "./templates";
import Auth from "./Auth"
const Router = () => {
return (
<Switch>
<Route exact path={"/signup"} component={SignUp} />
<Route exact path={"/signin"} component={SignIn} />
<Route exact path={"/signin/reset"} component={Reset} />
<Auth>
<Route exact path={"(/)?"} component={ProductList} />
<Route exact path={"/product/:id"} component={ProductDetail} />
<Route path={"/product/edit(/:id)?"} component={ProductEdit} />
<Route extct path={"/cart"} component={CartList} /> {*追記*}
</Auth>
</Switch>
);
};
export default Router
"/cart"
にルーティングします。
### 動作確認
全体の動作は「完成系イメージ」の通りです。
さいごに
今回の要点をおさらいすると、
- リスト表示を実装する際は、
map
メソッドでリストアイテム用コンポーネントをイテレートする。
以上です!次回、本格的に購入処理を実装していきます。
このような学習内容を日々呟いていますので、よろしければTwitter(@ddpmntcpbr)のフォローもよろしくお願いします。