λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
IT/React

[react] 동적 select box κ΅¬ν˜„ν•˜κΈ° (첫번째 ν•­λͺ© 선택에 따라 λ‹¬λΌμ§€λŠ” λ‹€μŒ 선택 λͺ©λ‘ κ΅¬ν˜„ν•˜κΈ°, 지역 선택 λ°•μŠ€)

by ITyranno 2024. 1. 13.
728x90
λ°˜μ‘ν˜•

 

 

 

 

 

 

ν”„λ‘œκ·Έλž˜λ° 세계λ₯Ό νƒκ΅¬ν•©μ‹œλ‹€.

 

 

 

 

 

 

 

동적 select box κ΅¬ν˜„ν•˜κΈ°

 

 

이번 ν”„λ‘œμ νŠΈμ—μ„œ 지역, λ‚œμ΄λ„ 선택을 순차적으둜 μž…λ ₯ν•  수 μžˆλŠ” Select Boxλ₯Ό κ΅¬ν˜„ν–ˆμŠ΅λ‹ˆλ‹€.

μ„ νƒν•˜λŠ” μ‹œλ„μ— 따라 ν•˜μœ„ μ£Όμ†Œ 선택 λͺ©λ‘μ΄ 달라지며, λ‚œμ΄λ„ 선택은 λ³„κ°œλ‘œ 항상 λ‚˜νƒ€λ‚˜μ•Ό ν–ˆμŠ΅λ‹ˆλ‹€.

일반적인 슀크둀 ν˜•νƒœμ˜ Select Boxκ°€ μ•„λ‹ˆλΌ λͺ©λ‘μ΄ μ œμ‹œλ˜μ–΄ 있고 클릭할 수 μžˆλŠ” κΈ°λŠ₯을 μ›ν–ˆμŠ΅λ‹ˆλ‹€.

 

 

κ΅¬ν˜„ ν™”λ©΄

 

 

 

Console

 

 

 

μž‘μ„± μ½”λ“œ

 

 

클릭해야 λ‚˜νƒ€λ‚˜λŠ” λͺ©λ‘μ΄ μ•„λ‹ˆλΌ λͺ©λ‘μ΄ μ œμ‹œλ˜μ–΄ μžˆλŠ” ν˜•νƒœμ˜ Select Boxλ₯Ό κ΅¬ν˜„ν•˜κΈ° μœ„ν•΄ λͺ©λ‘μ„ λ°°μ—΄ ν˜•νƒœλ‘œ μž‘μ„±ν•˜μ˜€μŠ΅λ‹ˆλ‹€.

 

useStateλ₯Ό μ‚¬μš©ν•˜μ—¬ μƒνƒœλ₯Ό μ—…λ°μ΄νŠΈν•˜λŠ” ν•¨μˆ˜λ₯Ό μ„ μ–Έν•˜μ˜€μŠ΅λ‹ˆλ‹€.

초기 μƒνƒœλ‘œλŠ” μ²« λ²ˆμ§Έ μ‹œλ„κ°€ μ„ νƒλ˜κ³ , λ‚˜λ¨Έμ§€λŠ” λΉˆ λ¬Έμžμ—΄λ‘œ μ„€μ •λ©λ‹ˆλ‹€.

const [selectedProvince, setSelectedProvince] = useState(provinces[0].name);

 

μ‹œλ„ λ³€κ²½ ν•Έλ“€λŸ¬μ—μ„œ μ•„λž˜ 뢀뢄은 μ‹œλ„ 선택 μ‹œ μ‹œκ΅°κ΅¬μ™€ μλ©΄λ™μ˜ 선택을 μ΄ˆκΈ°ν™”ν•˜λŠ” λΆ€λΆ„μž…λ‹ˆλ‹€.

        setSelectedDistrict('');
        setSelectedSubdistrict('');

 

 

 

Mselect.jsx

 

import style from './Mselect.module.css';
import React, { useState } from 'react';

function Mselect() {
    const provinces = [
        { id: 1, name: 'μ„œμšΈνŠΉλ³„μ‹œ' },
        { id: 2, name: '경기도' },
        { id: 3, name: 'μΈμ²œκ΄‘μ—­μ‹œ' },
        // λ‹€λ₯Έ μ‹œλ„ 데이터 μΆ”κ°€
    ];

    const districts = {
        μ„œμšΈνŠΉλ³„μ‹œ: ['강남ꡬ', 'κ°•μ„œκ΅¬', 'μ†‘νŒŒκ΅¬', /* ... */],
        경기도: ['μˆ˜μ›μ‹œ', 'μš©μΈμ‹œ', 'μ„±λ‚¨μ‹œ', /* ... */],
        μΈμ²œκ΄‘μ—­μ‹œ: ['쀑ꡬ', '남ꡬ', '동ꡬ', /* ... */],
        // λ‹€λ₯Έ μ‹œλ„μ˜ μ‹œκ΅°κ΅¬ 데이터 μΆ”κ°€
    };

    const subdistrict = {
        강남ꡬ: ['λŠ₯동', '청담동', 'λŒ€μΉ˜1동', /* ... */],
        μˆ˜μ›μ‹œ: ['κ³Όμ²œλ™', 'μ •μžλ™', 'μ•ˆμ–‘λ™', /* ... */],
        쀑ꡬ: ['강화읍', '솑해면', '문학동', /* ... */],
    }

    const difficulties = ['쉬움', '쀑간', '어렀움'];


    // μƒνƒœλ₯Ό μ •μ˜ν•©λ‹ˆλ‹€.
    const [selectedProvince, setSelectedProvince] = useState(provinces[0].name);
    const [selectedDistrict, setSelectedDistrict] = useState('');
    const [selectedSubdistrict, setSelectedSubdistrict] = useState('');
    const [difficulty, setDifficulty] = useState('');

    // μ‹œλ„ λ³€κ²½ ν•Έλ“€λŸ¬
    const handleProvinceChange = (provinceName) => {
        setSelectedProvince(provinceName);
        setSelectedDistrict('');
        setSelectedSubdistrict('');
        // ν˜„μž¬ λ‚œμ΄λ„ μƒνƒœκ°€ μ•„λ‹Œ, 직전에 μ„ νƒλœ λ‚œμ΄λ„λ₯Ό λ‘œκΉ…
        console.log(`μ‹œλ„: '${provinceName}', μ‹œκ΅°κ΅¬: '', 읍면동: '', λ‚œμ΄λ„: '${difficulty}'`);
    };

    // μ‹œκ΅°κ΅¬ λ³€κ²½ ν•Έλ“€λŸ¬
    const handleDistrictChange = (districtName) => {
        setSelectedDistrict(districtName);
        setSelectedSubdistrict('');
        // ν˜„μž¬ λ‚œμ΄λ„ μƒνƒœκ°€ μ•„λ‹Œ, 직전에 μ„ νƒλœ λ‚œμ΄λ„λ₯Ό λ‘œκΉ…
        console.log(`μ‹œλ„: '${selectedProvince}', μ‹œκ΅°κ΅¬: '${districtName}', 읍면동: '', λ‚œμ΄λ„: '${difficulty}'`);
    };

    // 읍면동 λ³€κ²½ ν•Έλ“€λŸ¬
    const handleSubdistrictChange = (subdistrictName) => {
        setSelectedSubdistrict(subdistrictName);
        // ν˜„μž¬ λ‚œμ΄λ„ μƒνƒœκ°€ μ•„λ‹Œ, 직전에 μ„ νƒλœ λ‚œμ΄λ„λ₯Ό λ‘œκΉ…
        console.log(`μ‹œλ„: '${selectedProvince}', μ‹œκ΅°κ΅¬: '${selectedDistrict}', 읍면동: '${subdistrictName}', λ‚œμ΄λ„: '${difficulty}'`);
    };

    // λ‚œμ΄λ„ λ³€κ²½ ν•Έλ“€λŸ¬
    const handleDifficultyChange = (level) => {
        setDifficulty(level);
        // μƒˆλ‘­κ²Œ μ„ νƒλœ λ‚œμ΄λ„λ₯Ό λ‘œκΉ…
        console.log(`μ‹œλ„: '${selectedProvince}', μ‹œκ΅°κ΅¬: '${selectedDistrict}', 읍면동: '${selectedSubdistrict}', λ‚œμ΄λ„: '${level}'`);
    };

    return (
        <>
            <div className={style.Mselectbox}>
                <div className={style.Mselect_main}>
                    <h1 className={style.Mselect_title}>
                        <img src={`${process.env.PUBLIC_URL}/img/mountainpath.svg`} alt="λ“±μ‚° 정보 μ•„μ΄μ½˜" className={style.icon1} />
                        λ“±μ‚° 정보</h1>
                </div>
            </div>

            <div className={style.Mselectbox1}>
                <h2>μ‹œλ„ 선택</h2>
                <div className={style.scrollableList}>
                    {provinces.map((province) => (
                        <div
                            key={province.id}
                            className={`${style.listItem} ${selectedProvince === province.name ? style.selected : ''}`}
                            onClick={() => handleProvinceChange(province.name)}
                        >
                            {province.name}
                        </div>
                    ))}
                </div>

                {selectedProvince && (
                    <>
                        <h2>μ‹œκ΅°κ΅¬ 선택</h2>
                        <div className={style.scrollableList}>
                            {districts[selectedProvince]?.map((district, index) => (
                                <div
                                    key={index}
                                    className={`${style.listItem} ${selectedDistrict === district ? style.selected : ''}`}
                                    onClick={() => handleDistrictChange(district)}
                                >
                                    {district}
                                </div>
                            ))}
                            {!districts[selectedProvince] && <div className={style.listItem}>μ‹œκ΅°κ΅¬κ°€ μ—†μŠ΅λ‹ˆλ‹€.</div>}
                        </div>

                        <h2>읍면동 선택</h2>
                        <div className={style.scrollableList}>
                            {selectedDistrict && subdistrict[selectedDistrict]?.map((sub, index) => (
                                <div
                                    key={index}
                                    className={`${style.listItem} ${selectedSubdistrict === sub ? style.selected : ''}`}
                                    onClick={() => handleSubdistrictChange(sub)}
                                >
                                    {sub}
                                </div>
                            ))}
                            {!subdistrict[selectedDistrict] && <div className={style.listItem}>읍면동이 μ—†μŠ΅λ‹ˆλ‹€.</div>}
                        </div>

                        <h2>λ‚œμ΄λ„ 선택</h2>
                        <div className={style.scrollableList}>
                            {difficulties.map((level, index) => (
                                <div
                                    key={index}
                                    className={`${style.listItem} ${difficulty === level ? style.selected : ''}`}
                                    onClick={() => handleDifficultyChange(level)}
                                >
                                    {level}
                                </div>
                            ))}
                        </div>



                    </>
                )}
            </div>
            <div className={style.Mselect_result}>
                <p>μ„ νƒλœ μ‹œλ„: {selectedProvince}</p>
                <p>μ„ νƒλœ μ‹œκ΅°κ΅¬: {selectedDistrict || 'μ„ νƒλ˜μ§€ μ•ŠμŒ'}</p>
                <p>μ„ νƒλœ 읍면동: {selectedSubdistrict || 'μ„ νƒλ˜μ§€ μ•ŠμŒ'}</p>
                <p>μ„ νƒλœ λ‚œμ΄λ„: {difficulty || 'μ„ νƒλ˜μ§€ μ•ŠμŒ'}</p>
            </div>
        </>
    );
}

export default Mselect;

 

 

 

 

 

 

 

Mselect.module.css

 

module.css ν˜•νƒœλ₯Ό μ‚¬μš©ν•  λ•Œμ˜ μž₯점은 클래슀 이름이 κ³ μœ ν•˜κ²Œ λ³€κ²½λ˜μ–΄ μŠ€νƒ€μΌμ΄ λ‹€λ₯Έ μ»΄ν¬λ„ŒνŠΈμ— 영ν–₯을 주지 μ•ŠλŠ”λ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€.

 

@font-face {
    font-family: 'GmarketSansLight';
    src: url('https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_2001@1.1/GmarketSansLight.woff') format('woff');
    font-weight: normal;
    font-style: normal;
}

.Mselectbox {
    padding-top: 7.5rem;
    justify-content: center;
    align-items: center;
    display: flex;
}

.Mselect_title {
    font-size: 2.5rem;
    display: flex;
    font-family: 'GmarketSansLight';
}

.icon1 {
    width: 3rem;
    height: 3rem;
    margin-right: 1rem;
}

.selector {
    cursor: pointer;
    /* 좔가적인 μŠ€νƒ€μΌ */
}

.Mselectbox1 {
    margin-top: 3rem;
    display: flex;
    justify-content: center;
    width: 100vw;
}

.scrollableList {
    max-height: 10rem;
    max-width: 15rem;
    overflow-y: auto;
    /* 수직 λ°©ν–₯으둜만 슀크둀 λ°” ν‘œμ‹œ */
    border: 0.1rem solid #ccc;
    /* 경계선 μŠ€νƒ€μΌ */
    margin-top: 5px;
    /* 상단 μ—¬λ°± */
    margin-right: 2rem;
    margin-left: 1rem;
    width: 100%;
    /* λ„ˆλΉ„ μ„€μ • */
    background: white;
    /* 배경색 */
    z-index: 10;
}

.listItem {
    padding: 10px;
    /* νŒ¨λ”© */
    cursor: pointer;
    /* 마우슀 포인터 λ³€κ²½ */
    border-bottom: 1px solid #eee;
    /* ν•˜λ‹¨ 경계선 μŠ€νƒ€μΌ */
}

.listItem:hover {
    background-color: #f7f7f7;
    /* ν˜Έλ²„μ‹œ 배경색 λ³€κ²½ */
}

.selected {
    background-color: #e9ecef;
    /* μ˜ˆμ‹œ 색상 */
}

.Mselect_result {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    margin-top: 2rem;
}

 

 

 

 

 

μœ„μ™€ 같은 λ°©μ‹μœΌλ‘œ reactλ₯Ό ν™œμš©ν•˜μ—¬ 동적 Select Boxλ₯Ό κ΅¬ν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

 

728x90
λ°˜μ‘ν˜•

loading