lesson-3_コンポーネントを作成しよう
📄 ファイルを追加しよう
このレッスンでは、Home画面
、Search画面
、ManageRooms画面
に必要なコンポーネントを作成していきます。
以下のようなファイル構造になるよう、ディレクトリとファイルを追加しましょう。
frontend/
├─ __mocks__/
├─ assets/
│ ├─ css/
│ ├─ img/
│ └─ js/
│ ├─ components/
+ │ │ ├─ AddRoom.js
+ │ │ ├─ FormDate.js
│ │ ├─ NavBar.js
+ │ │ └─ Room.js
│ ├─ near/
│ └─ pages/
│ ├─ GuestBookedList.js
│ ├─ Home.js
│ ├─ ManageBookings.js
│ ├─ ManageRooms.js
│ └─ Search.js
├─ App.js
├─ index.html
└─ index.js
🗓 日付を入力するフォームを作成しよう
まずは、日付を入力できるフォームを実装します。
以下のコードを追加しましょう。
frontend/assets/js/components/FormDate.js
import { useState } from "react";
import Button from "react-bootstrap/Button";
import Col from "react-bootstrap/Col";
import Form from "react-bootstrap/Form";
import Row from "react-bootstrap/Row";
import { useNavigate } from "react-router-dom";
const FormDate = () => {
const navigate = useNavigate();
const [date, setDate] = useState("");
const isFormFilled = () => date;
return (
<Form>
<Row
className="justify-content-center"
style={{ marginTop: "50px", marginBottom: "50px" }}
>
<Col xs="auto">
<Form.Control
type="date"
htmlSize="10"
onChange={(e) => {
setDate(e.target.value);
}}
/>
</Col>
<Col xs="auto">
<Button
variant="secondary"
// 検索する日付が入力されないとボタンを押せないように設定
disabled={!isFormFilled()}
// URLに入力された日付を入れて遷移先へ渡す
onClick={() => navigate(`/search/${date}`)}
>
Search
</Button>
</Col>
</Row>
</Form>
);
};
export default FormDate;
このようなフォームとボタンが実装されます。
追加した内容を見ていきましょう。
フォームの作成には、React BootstrapのFormを使用しました。type='date'
を指定することで、日付を入力するフォームができます。
指定した日付で部屋を探せるように、フォームの横にSearch ボタン実装しました。
<Button
variant="secondary"
// 検索する日付が入力されないとボタンを押せないように設定
disabled={!isFormFilled()}
// URLに入力された日付を入れて遷移先へ渡す
onClick={() => navigate(`/search/${date}`)}
>
Search
</Button>
ボタンの作成には、React BootstrapのButtonを使用しました。disabled=条件
を指定することで、ここでは日付が入力されないとボタンが押せないように設定しています。
Search ボタン を押すと、Search
画面へ遷移するように指定しています。この時、入力された日付(date
)を含めたパスを指定しています。この方法で遷移先のSearch.js
に日付を渡し、Search.js
ではパスから日付を取得するように実装します。
⌨️ 部屋のデータを入力するフォームを作成しょう
次に、オーナーが部屋のデータを登録するためのフォームを実装します。 以下のコードを追加してください。
frontend/assets/js/components/AddRoom.js
import PropTypes from "prop-types";
import { useState } from "react";
import Button from "react-bootstrap/Button";
import Form from "react-bootstrap/Form";
import Modal from "react-bootstrap/Modal";
const AddRoom = ({ save }) => {
// フォームで入力されたデータを取得・設定する
const [name, setName] = useState("");
const [beds, setBeds] = useState(0);
const [image, setImage] = useState("");
const [description, setDescription] = useState("");
const [location, setLocation] = useState("");
const [price, setPrice] = useState(0);
// 全ての項目が入力されたか確認する
const isFormFilled = () =>
name && beds && image && description && location && price;
// 入力フォームの表示・非表示を管理する
const [show, setShow] = useState(false);
const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
return (
<>
<Button onClick={handleShow}>POST</Button>
<Modal show={show} onHide={handleClose} centered>
<Modal.Header closeButton>
<Modal.Title>New Room</Modal.Title>
</Modal.Header>
<Form>
<Modal.Body>
{/* 部屋の名前 */}
<Form.Group className="mb-3" controlId="inputName">
<Form.Label>Name</Form.Label>
<Form.Control
type="text"
onChange={(e) => {
setName(e.target.value);
}}
placeholder="Enter name of Room"
/>
</Form.Group>
{/* 部屋の画像 */}
<Form.Group className="mb-3" controlId="inputUrl">
<Form.Label>Image</Form.Label>
<Form.Control
type="text"
placeholder="Image URL"
onChange={(e) => {
setImage(e.target.value);
}}
/>
</Form.Group>
{/* ベッドの数 */}
<Form.Group className="mb-3" controlId="inputBeds">
<Form.Label>Beds</Form.Label>
<Form.Control
type="number"
min={1}
onChange={(e) => {
setBeds(e.target.value);
}}
placeholder="Number of Beds"
/>
</Form.Group>
{/* 部屋の説明 */}
<Form.Group className="mb-3" controlId="inputDescription">
<Form.Label>Description</Form.Label>
<Form.Control
as="textarea"
placeholder="Description"
style={{ height: "80px" }}
onChange={(e) => {
setDescription(e.target.value);
}}
/>
</Form.Group>
{/* ホテルの場所 */}
<Form.Group className="mb-3" controlId="inputLocation">
<Form.Label>Location</Form.Label>
<Form.Control
type="text"
placeholder="Location"
onChange={(e) => {
setLocation(e.target.value);
}}
/>
</Form.Group>
{/* 一泊の価格(NEAR) */}
<Form.Group className="mb-3" controlId="inputPrice">
<Form.Label>Price</Form.Label>
<Form.Control
type="number"
min={0}
placeholder="Price"
onChange={(e) => {
setPrice(e.target.value);
}}
/>
</Form.Group>
</Modal.Body>
</Form>
<Modal.Footer>
<Button variant="outline-secondary" onClick={handleClose}>
Close
</Button>
<Button
variant="dark"
disabled={!isFormFilled()}
onClick={() => {
save({
name,
image,
beds,
description,
location,
price,
});
handleClose();
}}
>
Save room
</Button>
</Modal.Footer>
</Modal>
</>
);
};
AddRoom.propTypes = {
save: PropTypes.func.isRequired,
};
export default AddRoom;
このようなフォームが実装されます。
追加した内容を見ていきましょう。
import PropTypes from 'prop-types';
const AddRoom = ({ save }) => {
...
};
AddRoom.propTypes = {
save: PropTypes.func.isRequired,
};
export default AddRoom;
AddRoom
コンポーネントには、引数が渡されます。受け取る引数が関数であることを定義するために、prop-types
を使用しています。これにより、誤って関数以外のものが渡された時に予期せぬエラーが生じるのを防ぎます。
次に、&&
で全ての項目が入力されたかを確認する関数を定義しています。
const isFormFilled = () =>
name && beds && image && description && location && price;
今回のフォームは、ボタンを押したら表示されるように作成します。 React BootstrapのModalsを使用しています。
表示・非表示はboolean
型で制御しています。
// 入力フォームの表示・非表示を管理する
const [show, setShow] = useState(false);
const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
return (
<>
<Button onClick={handleShow}>POST</Button>
<Modal show={show} onHide={handleClose} centered>