I am trying to make a simple hotel reservation web app in react. Here is what I want to achieve. A user selects room
, adults
, and children
in number and reserve he's/her own hotels. The following screenshot depicts exactly what I want to do.
As you see from the above screenshot, when I click children's
Increment
button, I wanted to append a div having children
and their age. In the above screenshot, as I Incremented children value 2
times Two divs with children and their age has been appended.
I already design the component as follows. I want the logic here to apply.
Here is my Component code, I use tailwindcss
for styling
import React, { useState } from "react";
import rateIcon from "../../../assets/rate-cons.PNG";
import {
CheckIcon,
InformationCircleIcon,
WifiIcon,
ParkingIcon,
HeartIcon,
SwitchVerticalIcon,
AdjustmentsIcon,
MapIcon,
MinusIcon,
PlusIcon,
} from "@heroicons/react/outline";
import mapImage from "../../../assets/map.PNG";
import { LocationMarkerIcon } from "@heroicons/react/solid";
import DatePickers from "../DatePicker/DatePicker";
import {
HotelOutlined,
PeopleAltOutlined,
RoomOutlined,
RoomService,
} from "@material-ui/icons";
import {
ChildFriendly,
FamilyRestroomOutlined,
FamilyRestroomRounded,
} from "@mui/icons-material";
const Hero = () => {
const [rooms, setRooms] = useState(0);
const [show, setShow] = useState(false);
const showGuestInfo = () => setShow(!show);
const addRooms = () => {
setRooms(rooms 1);
};
const removeRooms = () => {
if (rooms > 1) {
setRooms(rooms - 1);
} else {
setRooms(rooms);
}
};
return (
<div className="p-3 flex w-full flex flex-col relative">
<div className="flex flex-col border-b border-gray">
<div className="p-2 flex justify-between items-center ">
<div className="flex text-sm items-center space-x-2">
<HotelOutlined />
<p>Rooms</p>
</div>
<div className="flex space-x-4 border p-2">
<p>
<MinusIcon
// onClick={removeRooms}
className="bg-gray-light h-6 cursor-pointer"
/>
</p>
<p>{rooms}</p>
<PlusIcon
// onClick={addRooms}
className=" bg-gray-light h-6 cursor-pointer"
/>
</div>
</div>
<div className="p-2 flex justify-between items-center">
<div className="flex text-sm items-center space-x-2">
<PeopleAltOutlined />
<p>Adults</p>
</div>
<div className="flex space-x-4 border p-2">
<p>
<MinusIcon
// onClick={removeRooms}
className="h-6 bg-gray-light cursor-pointer"
/>
</p>
<p>{rooms}</p>
<PlusIcon
// onClick={addRooms}
className="h-6 bg-gray-light cursor-pointer"
/>
</div>
</div>
<div className="p-2 flex justify-between items-center">
<div className="flex text-sm items-center space-x-2">
<FamilyRestroomOutlined />
<p>Childrens</p>
</div>
<div className="flex space-x-4 border p-2">
<p>
<MinusIcon
onClick={removeRooms}
className="h-6 bg-gray-light cursor-pointer"
/>
</p>
<p>{rooms}</p>
<PlusIcon
onClick={addRooms}
className="h-6 bg-gray-light cursor-pointer"
/>
</div>
</div>
</div>
<div className="border-t p-2 border-gray ">
<button className="p-2 border-t border-gray bg-black w-full text-white">
Update
</button>
</div>
</div>
);
};
How can I build this logic?
CodePudding user response:
The correct way to do this in React is to set the state of your component (or its parent). Then when you render the component, you use the state to decide what to render. So you don't "append" a div as much as you decide that you need a div at a certain spot due to the state.
In this case, you might have a list of children's ages as state. Clicking on the button will add an element to this list, probably defaulting to 0. Then for each child's age, you render a <div>
and a <select>
with that age. If the age is 0, then you have a message telling the user to select an age. When the user selects an age, you update the list at the correct position with that age.
Note that this can be implemented as a separate component to simplify the code in the top-level view.
The key thing here is that you never manipulate the DOM directly like you would with pure JavaScript or JQuery. Instead, you keep some data and use it to decide what to render.
CodePudding user response:
Since you don't have example, here is a repro on Stackblitz on how you can do it, and here is the code :
import React, { Component } from 'react';
import { render } from 'react-dom';
const App = () => {
const [children, setChildren] = React.useState(0);
return (
<div>
Children :{' '}
<input
type="number"
value={children}
onChange={(e) => setChildren(Number(e.target.value))}
/>
{Array.from(Array(Number(children)).keys()).map((child, index) => (
<div key={index}>
child of <input type="number" /> years old
</div>
))}
</div>
);
};
render(<App />, document.getElementById('root'));
The state children
store the number of children. We then just render as many div as this number by creating an array and mapping over it with this particular line :
Array.from(Array(Number(children)).keys())