체크 박스 필터 만들기
CheckBox 리스트 만들기 & CheckBox를 위한 UI 만들기
continent 값들이 너무 많다보니까 LandingPage에 넣으면 코드가 너무 길어진다. LandingPage 폴더에서 Sections 폴더를 만들고 Datas.js 파일을 만들어서 continent 값들을 저장하여 따로 구현해주자.
LandingPage/Sections/Datas.js
const continents = [
{
"_id": 1,
"name": "Africa"
},
{
"_id": 2,
"name": "Europe"
},
{
"_id": 3,
"name": "Asia"
},
{
"_id": 4,
"name": "North America"
},
{
"_id": 5,
"name": "South America"
},
{
"_id": 6,
"name": "Australia"
},
{
"_id": 7,
"name": "Antarctica"
}
]
export {
continents
}
그리고 CheckBox.js파일을 만들어서 이것도 Sections 폴더에 넣어서 관리해주자. 해당 파일은 위에 체크박스 필터 부분에 들어갈 코드 내용이다.
continent들을 LandingPage.js에 갖고와서 자식 컴포넌트인 CheckBox.js에 props인 list를 넣어주자.
LandingPage.js
import axios from 'axios';
import React, { useEffect, useState } from 'react'
import {Icon, Col, Row, Card, Carousel} from 'antd'
import Meta from 'antd/lib/card/Meta';
import ImageSlider from '../../utils/ImageSlider'
import CheckBox from '../LandingPage/Sections/CheckBox';
import { continents } from '../LandingPage/Sections/Datas';
function LandingPage() {
const [Products, setProducts] = useState([])
const [Skip, setSkip] = useState(0)
const [Limit, SetLimit] = useState(8)
const [PostSize, setPostSize] = useState(0)
useEffect(() => {
let body = {
skip:Skip,
limit:Limit
}
getProducts(body)
},[])
const loadMoreHandler = () => {
let new_skip = Skip + Limit
let body = {
skip:new_skip,
limit: Limit,
// 더보기 버튼을 눌렀을 때 가는 request라는 정보를 넣어줌
loadMore:true
}
getProducts(body)
setSkip(new_skip)
}
const getProducts = (body) => {
axios.post('/api/product/products', body)
.then(response => {
if(response.data.success){
if (body.loadMore) {
setProducts([...Products, ...response.data.productInfo])
} else {
setProducts(response.data.productInfo)
}
setPostSize(response.data.postSize)
}else {
alert('상품들을 갖고오는데 실패')
}
})
}
const renderCards = Products.map((product, index) => {
return (
<Col lg={6} md={8} xs={24} key={index}>
<Card
cover={<ImageSlider images={product.images} />}>
<Meta
title={product.title}
description={`${product.price}`}
/>
</Card>
</Col>
)
})
return (
<div style={{ width: '75%', margin: '3rem auto' }}>
<div style={{textAlign: 'center'}}>
<h2>Let's Travel Anywhere <Icon type="rocket"/></h2>
</div>
{/* Filter */}
{/* CheckBox */}
<CheckBox list={continents} />
{/* RadioBox */}
{/* Search */}
<Row gutter={[16, 16]}>
{renderCards}
</Row>
{PostSize >= Limit &&
<div style={{ display: 'flex', justifyContent: 'center' }}>
<button onClick={loadMoreHandler}>더보기</button>
</div>
}
</div>
)
}
export default LandingPage
CheckBox.js
import React from 'react'
import { Collapse, Checkbox } from 'antd';
const { Panel } = Collapse;
function CheckBox(props) {
const renderCheckboxLists = () => props.list && props.list.map((value, index) => (
<React.Fragment key={index}>
<Checkbox />
<span>{value.name}</span>
</React.Fragment>
))
return (
<div>
<Collapse defaultActiveKey={['1']}>
<Panel header="This is panel header 1" key="1">
{renderCheckboxLists()}
</Panel>
</Collapse>
</div>
)
}
export default CheckBox
onChange Function 만들기 & Checked State를 부모 컴포넌트로 업데이트 하기
checkBox를 컨트롤할 때 checked라는 속성을 이용하면 된다.
CheckBox 컴포넌트에서 onChange 이벤트에 함수를 넣어줌으로써 체크박스를 체크하거나 해제할 때 트리거가 호출되도록 구현하자.
LandingPage.js
import axios from 'axios';
import React, { useEffect, useState } from 'react'
import {Icon, Col, Row, Card, Carousel} from 'antd'
import Meta from 'antd/lib/card/Meta';
import ImageSlider from '../../utils/ImageSlider'
import CheckBox from '../LandingPage/Sections/CheckBox';
import { continents } from '../LandingPage/Sections/Datas';
function LandingPage() {
const [Products, setProducts] = useState([])
const [Skip, setSkip] = useState(0)
const [Limit, SetLimit] = useState(8)
const [PostSize, setPostSize] = useState(0)
const [Filters, setFilters] = useState({
continents:[],
price:[]
})
useEffect(() => {
let body = {
skip:Skip,
limit:Limit
}
getProducts(body)
},[])
const loadMoreHandler = () => {
let new_skip = Skip + Limit
let body = {
skip:new_skip,
limit: Limit,
// 더보기 버튼을 눌렀을 때 가는 request라는 정보를 넣어줌
loadMore:true
}
getProducts(body)
setSkip(new_skip)
}
const getProducts = (body) => {
axios.post('/api/product/products', body)
.then(response => {
if(response.data.success){
if (body.loadMore) {
setProducts([...Products, ...response.data.productInfo])
} else {
setProducts(response.data.productInfo)
}
setPostSize(response.data.postSize)
}else {
alert('상품들을 갖고오는데 실패')
}
})
}
const renderCards = Products.map((product, index) => {
return (
<Col lg={6} md={8} xs={24} key={index}>
<Card
cover={<ImageSlider images={product.images} />}>
<Meta
title={product.title}
description={`${product.price}`}
/>
</Card>
</Col>
)
})
const handleFilters = (filters, category) => {
}
return (
<div style={{ width: '75%', margin: '3rem auto' }}>
<div style={{textAlign: 'center'}}>
<h2>Let's Travel Anywhere <Icon type="rocket"/></h2>
</div>
{/* Filter */}
{/* CheckBox */}
{/* 밑에 매개변수로 filters와 continents를 받았는데 이때 continents는 카테고리이다.
필터를 구현할 때 continent 뿐만 아니라 가격 필터도 구현해야 되기 때문에 구분해주기 위해 카테고리를 매개변수로 넣어준다.
*/}
<CheckBox list={continents} handleFilters={filters => handleFilters(filters, 'continents')} />
{/* RadioBox */}
{/* Search */}
<Row gutter={[16, 16]}>
{renderCards}
</Row>
{PostSize >= Limit &&
<div style={{ display: 'flex', justifyContent: 'center' }}>
<button onClick={loadMoreHandler}>더보기</button>
</div>
}
</div>
)
}
export default LandingPage
위에 CheckBox 컴포넌트 부분 코드를 간략하게 설명하자면,
handleFilters = {} 이때 함수는 자식 컴포넌트인 CheckBox에 props로 준 함수이다.
특정 체크박스를 체크하거나 해제할 때 트리거가 호출된다.
밑에 코드를 보면 props로 받은 handleFIlters 함수를 호출하는 부분이 있는데, 이 부분에서 트리거가 호출 됐을 때 과정을 처리한 후에 새로 갱신된 Chcked state를 매개변수로 넣어준다.
이렇게 되면 위 코드의 filters => 이 부분에 있는 filters 변수에 위에서 주었던 매개변수(새로 갱신된 Chcked state)가 들어가고,
이 filters 변수를 부모 컴포넌트에 있는 handleFilters 함수에 매개변수로 넣어주고, 두번째 인자로 'continent'가 들어가면서 바로 호출하게 된다.
강사님께서 함수 이름을 똑같이 지어서 조금 헷갈릴 수도 있는데 복습할 때 다시 천천히 생각해보자.
CheckBox.js
import React, { useState } from 'react'
import { Collapse, Checkbox } from 'antd';
const { Panel } = Collapse;
function CheckBox(props) {
// 체크된 것들을 저장하는 state
const [Checked, setChecked] = useState([])
const handleToggle = (value) => {
// 누른 것의 index를 구하고
const currentIndex = Checked.indexOf(value)
// 전체 Checked된 State에서 현재 누른 CheckBox가
const newChecked = [...Checked]
// 전체 Checked된 State에서 없는 checkBox는 -1 값이 나온다. 만약 있다면 그 checkBox의 index값이 나온다.
if(currentIndex === -1){
// 없다면 State에 넣어준다.
newChecked.push(value)
}
else {
// 있다면 빼주고
newChecked.splice(currentIndex, 1);
}
// 새로 갱신된 newChecked 배열을 Chcked로 설정해주자.
setChecked(newChecked)
props.handleFilters(newChecked)
}
const renderCheckboxLists = () => props.list && props.list.map((value, index) => (
<React.Fragment key={index}>
{/* value의 _id 값은 Datas.js 파일에서 갖고 부분에서 _id값이다. */}
<Checkbox onChange={() => handleToggle(value._id)}
checked={Checked.indexOf(value._id) === -1 ? false : true}
/>
<span>{value.name}</span>
</React.Fragment>
))
return (
<div>
<Collapse defaultActiveKey={['1']}>
<Panel header="This is panel header 1" key="1">
{renderCheckboxLists()}
</Panel>
</Collapse>
</div>
)
}
export default CheckBox