인프런 커뮤니티 질문&답변

wodus604님의 프로필 이미지
wodus604

작성한 질문수

리액트 셀렉트 박스 질문드려요

작성

·

362

0

import React, { useState } from 'react';
import { Button } from "../../ui/button";
import {
    Dialog,
    DialogContent,
    DialogFooter,
    DialogHeader,
    DialogTitle,
    DialogTrigger,
    DialogClose
} from "../../ui/dialog";
import { Input } from "../../ui/input";
import SelectBox from "./SelectBox";

function UserRegistrationButton() {
    const [id, setId] = useState('');
    const [name, setName] = useState('');
    const [password, setPassword] = useState('');
    const [confirmPassword, setConfirmPassword] = useState('');
    const [ip, setIp] = useState('');
    const [selectedAuthority, setSelectedAuthority] = useState("");

    const items = [
        { value: '1', label: '일반' },
        { value: '2', label: '마스터' },
    ];

    const handleDataChange = (newData) => {
        setSelectedAuthority(newData);
    };

    const handleSubmit = () => {
        console.log({ id, name, password, confirmPassword, ip, selectedAuthority });
    };

    return (
        <Dialog>
            <DialogTrigger asChild>
                <Button className="w-full">사용자 등록</Button>
            </DialogTrigger>
            <DialogContent className="w-full max-w-2xl">
                <DialogHeader>
                    <DialogTitle className="text-variant-h4-bold">사용자 등록</DialogTitle>
                </DialogHeader>
                <div className="grid gap-5 py-3">
                    <div className="flex gap-3">
                        <div className="grid grid-cols-10 w-full">
                            <div className="grid col-span-2 content-center">
                                아이디
                            </div>
                            <Input
                                id="userId"
                                className="col-span-8"
                                value={id}
                                onChange={e => setId(e.target.value)}
                            />
                        </div>
                        <div className="grid grid-cols-10 w-full">
                            <div className="grid col-span-2 content-center">
                                이름
                            </div>
                            <Input
                                id="name"
                                className="col-span-8"
                                value={name}
                                onChange={e => setName(e.target.value)}
                            />
                        </div>
                    </div>
                    <div className="flex gap-3">
                        <div className="grid grid-cols-10 w-full">
                            <div className="text-sm grid col-span-2 content-center">
                                비밀번호
                            </div>
                            <Input
                                id="password"
                                className="col-span-8"
                                type="password"
                                value={password}
                                onChange={e => setPassword(e.target.value)}
                            />
                        </div>
                        <div className="grid grid-cols-10 w-full">
                            <div className="text-sm grid col-span-2 content-center">
                                비밀번호 확인
                            </div>
                            <Input
                                id="confirmPassword"
                                className="col-span-8"
                                type="password"
                                value={confirmPassword}
                                onChange={e => setConfirmPassword(e.target.value)}
                            />
                        </div>
                    </div>
                    <div className="flex gap-3">
                        <div className="grid grid-cols-10 w-full">
                            <div className="grid col-span-2 content-center">
                                권한
                            </div>
                            <SelectBox
                                className="col-span-8"
                                items={items}
                                onDataChange={handleDataChange}
                            />
                        </div>
                        <div className="grid grid-cols-10 w-full">
                            <div className="grid col-span-2 content-center">
                                접속 IP
                            </div>
                            <Input
                                id="IP"
                                className="col-span-8"
                                value={ip}
                                onChange={e => setIp(e.target.value)}
                            />
                        </div>
                    </div>
                </div>
                <DialogFooter>
                    <div className='flex justify-center gap-5'>
                        <DialogClose asChild>
                            <Button onClick={handleSubmit} size="xxl">등록</Button>
                        </DialogClose>
                        <DialogClose asChild>
                            <Button variant="secondary" size="xxl">취소</Button>
                        </DialogClose>
                    </div>
                </DialogFooter>
            </DialogContent>
        </Dialog>
    );
}

export default UserRegistrationButton;
import React, { useState, useEffect } from 'react';
import {
    Select,
    SelectValue,
    SelectTrigger,
    SelectContent,
    SelectItem,
} from '../../ui/select';

interface SelectBoxProps {
    className?: string;
    items: { value: string; label: string }[];
    onDataChange: any;
}

const SelectBox: React.FC<SelectBoxProps> = ({ className, items, onDataChange }) => {
    const [selectedValue, setSelectedValue] = useState("");

    const sendDataToParent = (payload) => {
        onDataChange(payload);
        console.log(payload, selectedValue)
    };

    return (
        <Select>
            <SelectTrigger className={className}>
                <SelectValue placeholder="권한을 선택하세요." />
            </SelectTrigger>
            <SelectContent>
                {items.map(item => (
                    <SelectItem key={item.value} value={item.value} onClick={() => sendDataToParent(item.label)}>
                        {item.label}
                    </SelectItem>
                ))}
            </SelectContent>
        </Select>
    );
};

export default SelectBox;

제 코드인데요 현재 shadcn/ui를 쓰면서 진행중인데요
셀렉트 박스가 하위컴포넌트이고 상위 컴포넌트로 셀렉트 박스가 선택한 값을 보내고 싶은데 할 수 있는 방법 다 해도 안되더라고요 현재 코드는 콜백함수를 이용하여 데이터를 호출하려고 했는데 실패했습니다. 이럴 때는 무조건 리덕스나 리코일 같은 전역으로 상태관리를 해서 값을 주는 방법 밖에는 없나요 ? 아니면 다른 방법이 있으면 알려주세요

답변 1

0

안녕하세요, 인프런 AI 인턴입니다.
wodus604님, 리액트에서 하위 컴포넌트에서 상위 컴포넌트로 데이터를 전달하는 전형적인 방식은 props를 통한 콜백 함수 전달입니다. 제공해 주신 코드를 보면, 이미 onDataChange라는 콜백 함수를 통해 상위 컴포넌트로 데이터를 전달하려고 하셨으나 실패하셨다고 합니다.

현재 SelectBox 컴포넌트에서 sendDataToParent 함수를 호출할 때 item.label 값을 전달하고 계신데, onDataChange 함수가 전달된 값(newData에 해당하는 부분)을 올바로 처리하고 있는지 확인해 보셔야 합니다.

또한 SelectItem에 설정된 onClick 핸들러에서 sendDataToParent 함수를 실행하시는데, Select 컴포넌트 라이브러리가 제공하는 props나 메소드를 사용하지 않고 기본 HTML의 onClick을 그대로 사용하고 계신 것으로 보입니다. 이 부분이 shadcn/ui 라이브러리에서 올바른 이벤트 핸들링을 수행하지 못해 발생하는 문제일 수 있습니다. 관련 라이브러리의 문서를 확인하시어 올바른 핸들러 설정을 하셨는지 확인해 보시기 바랍니다.

리덕스나 리코일 같은 전역 상태 관리 라이브러리는 대규모 상태를 관리할 때 유용하지만, 단순히 부모와 자식 간의 상태 전달을 위해 꼭 필요한 것은 아닙니다. 작성하신 코드 상의 문제를 해결하는 것이 우선이며, 필요에 따라 상태 lifting, Context API, 전역 상태 관리 라이브러리 등을 검토하는 것이 좋겠습니다.

아래는 몇 가지 점검해 볼 수 있는 사항들입니다:
1. onDataChange 콜백 함수가 상위 컴포넌트에서 정의된 대로 올바르게 동작하는지 확인하기.
2. SelectBox 컴포넌트에서 사용하는 라이브러리의 이벤트 핸들링 방식을 문서에서 확인하고 적용하기.
3. 상태를 올바르게 업데이트하는지, 불필요한 리렌더링이 발생하지 않는지 확인하기.

만약 이런 점검 이후에도 문제를 해결하지 못하신다면 ‘문의하기’ 기능을 이용하여 좀 더 구체적인 코드 리뷰나 도움을 받으시는 것도 좋은 방법입니다.

wodus604님의 프로필 이미지
wodus604

작성한 질문수

질문하기