react-shop-web/front & back

라디오 박스 필터 만들기

tjdvyzl 2023. 2. 4. 02:33

라디오 박스 필터는 CheckBox 필터 만드는 과정과 거의 비슷하기 때문에 복습할 땐 CheckBox 필터 글을 보자.

 

#1

RadioBox 리스트 데이터 만들기


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"
    }
]

const price = [
    {
        "_id": 0,
        "name": "Any",
        "array": []
    },
    {
        "_id": 1,
        "name": "$0 to $199",
        "array": [0, 199]
    },
    {
        "_id": 2,
        "name": "$200 to $249",
        "array": [200, 249]
    },
    {
        "_id": 3,
        "name": "$250 to $279",
        "array": [250, 279]
    },
    {
        "_id": 4,
        "name": "$280 to $299",
        "array": [280, 299]
    },
    {
        "_id": 5,
        "name": "More than $300",
        "array": [300, 1500000]
    }
]


export {
    continents,
    price
}

 

 

 


RadioBox를 위한 UI 만들기 & onChange Function 만들기 &

Checked State를 부모 컴포넌트로 업데이트 하기 


 

Sections 폴더에 RadioBox.js 파일을 만든다.

 

 

https://ant.design/components/radio

 

Radio - Ant Design

Passing the name property to all input[type="radio"] that are in the same Radio.Group. It is usually used to let the browser see your Radio.Group as a real "group" and keep the default behavior. For example, using left/right keyboard arrow to change your s

ant.design

 

 

RadioBox.js

더보기
import React, { useState } from 'react'
import { Collapse, Radio } from 'antd';

const { Panel } = Collapse;

function RadioBox(props) {

    const [Value, setValue] = useState(0)

    const renderRadioBox = () => (
        props.list && props.list.map(value => (
            <Radio key={value._id} value={value._id}>{value.name}</Radio>
        ))    
    )

    const handleChange = (e) => {
        setValue(e.target.value)
        props.handleFilters(e.target.value)
    }

  return (
    <div>
          <Collapse defaultActiveKey={['1']}>
            <Panel header="This is panel header 1" key="1">
                <Radio.Group onChange={handleChange} value={Value}>
                    {renderRadioBox()}
                </Radio.Group>
            </Panel>    
        </Collapse>
    </div>
  )
}

export default RadioBox

 

위 코드에서 Radio.Gropup 컴포넌트는 모든 Radio 컴포넌트들을 감싸는 역할을 하므로 renderRadioBox 함수 자체를 감싸줘야한다.

 

Radio.Group 컴포넌트가 감싸는 Radio 컴포넌트들이 여러 개가 될 수 있다. 그 Radio 컴포넌트마다 value가 다르다.

Radio.Group 컴포넌트에 있는 value와 Radio 컴포넌트의 value가 같으면 이것이 클릭이 된 상태이다. 

그래서 onChange 이벤트로 Radio.Group 컴포넌트의 value값을 컨트롤 하면 된다.

즉, Radio 컴포넌트를 클릭 할 때 마다 Radio.Group에 있는 handleChange Function이 작동하면서 

Radio 컴포넌트에 있는 value가 Value State를 변경해서 Radio.Group 컴포넌트의 value값이 바뀌는 것이다.  

 

이렇게 되면 라디오 컴포넌트는 오직 하나만 선택이 가능하게 된다.

 


 

#2

 

handleFilter Function 만들기


price 필터 같은 경우 continents 필터와 다른 것을 조금 넣어줘야 한다.

RadioBox 컴포넌트에서 선택한 라디오 박스의 value는 그 컴포넌트의 id값이 들어온다. 만약 두번째 라디오 박스를 선택했다면 filters 값으로 1이 들어갈 것이다. 

CheckBox 컴포넌트 때 처럼 라디오 컴포넌트를 통해 필터링이 됐다면 바로 handleFilters 함수가 호출되면서 매개변수로 위에서 말했던 filters값과 'price' 카테고리가 들어갈 것이다. 

 

 

 


handleFilter를 위한 handlePrice function 만들기


밑에 코드를 LandingPage.js 에 넣어주자.

    const handlePrice = (value) => {
        const data = price;
        let array = [];

        // 현재 data는 datas.js에서 갖고온 price 데이터들이 들어감 
        // 여기서 key는 0, 1, 2 ... 이런식으로 들어감 
        for (let key in data) {
            // 매개변수로 받은 value는 price 필터의 filters 이다.
            // 그리고 price 필터의 filters 데이터는 각 price 컴포넌트들의 id값들 즉, 0, 1, 2 ... 이다.
            // parseInt로 감싸준 이유는 혹시라도 string이 들어오면 숫자로 바꿔주기 위해서이다.
            if (data[key]._id === parseInt(value, 10)) {
                array = data[key].array;
            }
        }

        return array;
    }

    const handleFilters = (filters, category) => {
        
        const newFilters = { ...Filters }
        
        newFilters[category] = filters

        if (category === 'price') {
            let priceValues = handlePrice(filters)
            newFilters[category] = priceValues
        }

        showFilteredResults(newFilters)
        
        // setFilters를 통해 기존에 있던 contients 필터들과 바뀐 price 필터들을 새로 저장해주자.
        setFilters(newFilters)
    }

 

위 코드에서 주석으로 말했던 것처럼 RadioBox를 통해 필터링을 거치면 그때 받는 값은 _id값이다. 즉, Datas.js에서 정의해주었던 변수들의 _id값이므로 0, 1, 2, 3 이런식의 값이 들어간다. 

여기서 handlePrice 함수가 하는 역할은 Datas.js에 있는 모든 price 변수를 반복문으로 탐색하면서 매개변수로 받은 _id값과 맞는 변수를 찾아서 그 변수의 배열 값을 리턴한다. 즉, [0, 199], [200, 249] 이런 식의 배열이 리턴된다.

 

이것을 'price'를 category 매개변수로 받은 handleFilters 함수에서 if문을 이용하여 newFilters['price'] = [handlePrice 함수를 통해 리턴된 배열값] 을 넣어주는 과정이다.

 

 


필터 기능을 위한 getProduct Route 수정하기


/products 라우트에서 반복문 부분을 조금 바꿔줘야 한다.

    for (let key in req.body.filters) {
        if (req.body.filters[key].length > 0) {
            if (key === "price") {
                findArgs[key] = {
                    // greater than equal
                    $gte: req.body.filters[key][0],
                    // less than equal 
                    $lte: req.body.filters[key][1]
                }
            } else {
                findArgs[key] = req.body.filters[key];
            }
        }
    }

 

price 필터같은 경우 handlePrice 함수를 통해 [0,199] 이런식의 배열값을 리턴했었다. 

위 코드에서 price를 필터링 하는 과정일 때, findArgs['price'] = [0,199] 이런 식의 값이 들어가 있는 상태이다.

이때 0도 포함하고 199도 포함시켜주기 위해서 몽고DB에서 지원해주는 $gte, $lte를 이용하여 0과 199까지 포함시켜주는 과정이다.