기본 Nav 에 이어서 활성화된 Nav 를 회고한다.
활성화된 Nav (ActivatedNav.js)
import { useNavigate } from 'react-router-dom';
import React, { useEffect, useState } from 'react';
import styled from 'styled-components';
import Person from './Person';
import { FaSearch } from 'react-icons/fa';
function SearchNav({ setIsClickedNav, isClickedNav }) {
const [whichIsClicked, setWhichIsClicked] = useState('');
const [personCardData, setPersonCardData] = useState([]);
const [searchLocation, setSerchLocation] = useState('');
const [checkInDate, setCheckInDate] = useState('');
const [checkOutDate, setCheckOutDate] = useState('');
const [personNum, setPersonNum] = useState(0);
const [childNum, setChildNum] = useState(0);
const navigate = useNavigate();
useEffect(() => {
fetch('data/PersonData.json')
.then(res => res.json())
.then(data => {
setPersonCardData(data);
});
}, []);
// useEffect (side effect) 에서 fetch 함수로 목데이터 PersonData.json 파일을 불러와
// 초기 state 인 personCardData 이름의 빈 배열안에 업데이트 한다
const goToListPage = () => {
if (!searchLocation) {
alert('장소를 입력해주세요');
return;
} else if (!checkInDate) {
alert('체크인 날짜를 입력해주세요');
return;
} else if (!checkOutDate) {
alert('체크아웃 날짜를 입력해주세요');
return;
} else if (!personNum + childNum) {
alert('인원을 선택해주세요');
return;
}
setWhichIsClicked('ㅇ');
navigate(
`roomlist?location=${searchLocation}&check_in=${checkInDate}&check_out=${checkOutDate}&guest=${
personNum + childNum
}`
);
};
const userSelectThis = buttonName => {
setWhichIsClicked(buttonName);
};
const plusPersonNumber = title => {
if (title === '성인') {
setPersonNum(personNum + 1);
} else if (title === '어린이') {
setChildNum(childNum + 1);
}
};
const minusPersonNumber = title => {
if (title === '성인') {
setPersonNum(personNum - 1);
} else if (title === '어린이') {
setChildNum(childNum - 1);
}
};
const changeLocationInput = e => {
if (e.target.name === 'location') {
setSerchLocation(e.target.value);
} else if (e.target.name === 'checkIn') {
setCheckInDate(e.target.value);
} else if (e.target.name === 'checkOut') {
setCheckOutDate(e.target.value);
}
};
return (
<Navigation>
<Room>
<div className="text">숙소</div>
</Room>
<SearchBarContainer>
<SearchBar type="button">
<Location
whichIsClicked={whichIsClicked}
onClick={() => userSelectThis('location')}
>
//onClick시 userSelectThis 함수를 실행해 setWhichIsClicked의 인자를 location으로 업데이트해서
// whichIsClicked가 location이 된다 (whichIsClicked={whichIsClicked})
<LocationDiv>
<LocationText>위치</LocationText>
<LocationInput
placeholder="어디로 여행가세요?"
value={searchLocation}
onChange={changeLocationInput}
name="location"
/>
// LocationInput 의 value 값은 searchLocation 의 상태값으로 설정하고
// onChange event 로 ChangeLocationInput 함수를 실행한다
// ChangeLocationInput 함수의 기능은 e.target.name이
// location 인지 checkIn 인지 CheckOut 인지에 따라 각각의 초기 상태값들을
// e.target.value 값으로 업데이트 한다
</LocationDiv>
</Location>
<CheckIn
whichIsClicked={whichIsClicked}
onClick={() => userSelectThis('checkIn')}
>
//onClick시 userSelectThis 함수를 실행해 setWhichIsClicked의 인자를 checkIn 으로 업데이트해서
// whichIsClicked가 checkIn 이 된다 (whichIsClicked={whichIsClicked})
<CheckInDiv>
<CheckInText>체크인</CheckInText>
<CheckInInput
placeholder="날짜입력"
value={checkInDate}
onChange={changeLocationInput}
name="checkIn"
/>
// value는 checkInDate 의 초기상태값은 공백으로 설정한다
// onChange 이벤트로 changeLocationInput 을 실행시켜 e.target.name 값에 따라 각 input 의 value 값을 업데이트한다
</CheckInDiv>
</CheckIn>
<CheckOut
whichIsClicked={whichIsClicked}
onClick={() => userSelectThis('checkOut')}
>
//onClick시 userSelectThis 함수를 실행해 setWhichIsClicked의 인자를 checkOut 으로 업데이트해서
// whichIsClicked가 checkOut 이 된다 (whichIsClicked={whichIsClicked})
<CheckOutDiv>
<CheckOutText>체크아웃</CheckOutText>
<CheckOutInput
placeholder="날짜 입력"
value={checkOutDate}
onChange={changeLocationInput}
name="checkOut"
/>
// value는 checkOutDate 의 초기상태값은 공백으로 설정한다
// onChange 이벤트로 changeLocationInput 을 실행시켜 e.target.name 값에 따라 각 input 의 value 값을 업데이트한다
</CheckOutDiv>
</CheckOut>
<PersonNum whichIsClicked={whichIsClicked}>
<PersonDiv onClick={() => userSelectThis('personNum')}>
//onClick시 userSelectThis 함수를 실행해 setWhichIsClicked의 인자를 personNum 으로 업데이트해서
// whichIsClicked가 personNum 이 된다 (whichIsClicked={whichIsClicked})
<PersonText>인원</PersonText>
<PersonInput>
{personNum + childNum > 0
? `게스트 ${personNum + childNum}명`
: '게스트 추가'}
// personNum, childNum 을 더한 상태값이 0보다 크면 '게스트 (성인 + 어린이) 명' 으로 렌더링하고
// 아닐경우 '게스트 추가' 로 렌더링한다
</PersonInput>
</PersonDiv>
<MapContainer>
{whichIsClicked === 'personNum' &&
personCardData.map(card => {
return (
<Person
key={card.id}
id={card.id}
title={card.title}
subtitle={card.subTitle}
backgroundcolor={card.backgroundcolor}
personNum={personNum}
childNum={childNum}
plusPersonNumber={plusPersonNumber}
minusPersonNumber={minusPersonNumber}
/>
);
})}
// whichIsClicked 값이 personNum 이고 personCardData.map 의 값이 있다면
// 자식 컴포넌트 Person.js 에게 물려준 key, id, title, subtitle, backgroundcolor, 속성값들과
// personNum, childNum, 상태값들과
// plusPersonNumver, minusPersonNumber 함수들을 props 로 넘겨주고
// import 해서 가져온 자식 컴포넌트 Person.js를 id 별로 전달된 속성값, 상태값, 함수들을 가져와서 map 메서드로 인원수 부분을 렌더링 한다
</MapContainer>
<SearchZoom
type="button"
onClick={() => {
return goToListPage(), setIsClickedNav(!isClickedNav);
}}
>
// 검색버튼 클릭시 gotolistpage 함수를 실행시켜 각 input 의 상태값들이
// 공백이면 alert 창을 띄우고
// Nav.js 컴포넌트에서 물려받은 setisClickednav(!isClickednav) 함수를 실행시켜
// isClickedNav 초기상태값인 false 를 true 로 업데이트해서 Activated된 Nav를 비활성화시킨다
// 만약 각 input 의 상태값이 true 라면 setWhichIsClicked('ㅇ') 함수를 실행시켜
// whichIsClicked 의 공백인 상태값을 'ㅇ' 으로 업데이트해서 각 input 창의 onClick event의 함수인
// userSelectThis 를 실행하지 못하도록 한다 ( location 도 checkIn, checkOut 도 personNum 도 아닌 'ㅇ' 으로 바꿔줌으로써 )
// 그리고 roomlist 페이지로 이동하면서 쿼리파라미터로 위치값, 체크인 날짜값, 체크아웃 날짜값, 게스트 수의 상태값들을 전달한다
// (이 정보들을 가지고 roomlist 페이지에서 필터링된 데이터들을 볼 수 있다)
<FaSearch className="search" />
</SearchZoom>
</PersonNum>
</SearchBar>
</SearchBarContainer>
</Navigation>
);
}
PersonData.json
[
{
"id": 1,
"title": "성인",
"subTitle": "만 13세 이상",
"backgroundcolor": "rgb(217, 59, 48)"
},
{
"id": 2,
"title": "어린이",
"subTitle": "만 2~12세",
"backgroundcolor": "rgb(217, 59, 48)"
}
]
Person.js (인원수 설정하는 컴포넌트)
function PersonCard({
title,
subtitle,
backgroundcolor,
personNum,
childNum,
plusPersonNumber,
minusPersonNumber,
}) {
return (
<Container backgroundcolor={backgroundcolor}>
<Text>{title}</Text>
<SubText>{subtitle}</SubText>
<PlusMinusContainer>
<Minus
value="minusBtn"
onClick={() => minusPersonNumber(title)}
disabled={personNum < 1 ? true : childNum < 1 ? true : false}
>
// onclick event 로 부모로부터 물려받은 minusPersonNumber 함수를 실행하고 title 을 인자로 가진다
// minusPersonNumber 함수의 기능은 title 이 '성인'이라면 personNum 상태값을
// -1 해서 업데이트하고 title 이 '어린이'라면 childNum 상태값을 -1 해서 업데이트한다
// personNum과 childNum의 상태값이 1보다 작으면 버튼이 비활성화가 된다
<MinusSpan>-</MinusSpan>
</Minus>
<Count>{title === '성인' ? personNum : childNum}</Count>
// title 상태값이 '성인'인지 아닌지에 따라서 <Count> 태그의 값이 적용된다 (성인 or 어린이)
<Plus value="plusBtn" onClick={() => plusPersonNumber(title)}>
// onclick event 로 부모로부터 물려받은 plusPersonNumber 함수를 실행하고 title 을 인자로 가진다
// plusPersonNumber 함수의 기능은 title 이 '성인'이라면 personNum 상태값을
// +1 해서 업데이트하고 title 이 '어린이'라면 childNum 상태값을 +1 해서 업데이트한다
<PlusSpan>+</PlusSpan>
</Plus>
</PlusMinusContainer>
</Container>
);
}
// 부모 컴포넌트로부터 물려받은 속성값들을 가지고 부모 컴포넌트 (ActivatedNav.js) 에서 하나씩 렌더링된다
import React from 'react';
import { useNavigate } from 'react-router-dom';
import styled from 'styled-components';
function LoginPopUp() {
const navigate = useNavigate();
const LogOutUser = e => {
navigate('/');
};
return (
<LoginPop>
<Mypage onClick={() => navigate('mypage')}>마이페이지</Mypage>
// onClick 이벤트가 발생할때마다 navigate 함수를 실행시키는데 인자로 'mypage'를 가진다
// 즉 mypage 주소로 이동한다
<Logout onClick={LogOutUser}>로그아웃</Logout>
</LoginPop>
// onClick 이벤트로 LogOutUser 함수가 실행되서 / (메인페이지) 주소로 이동한다
);
}
시현 영상 : https://www.youtube.com/watch?v=J1Jll-h7MRE
깃헙 주소 : https://github.com/wecode-bootcamp-korea/26-2nd-WeAreBnB-frontend