์๋ ํ์ธ์. ์บก์คํค ํ๋ก์ ํธ ์ค ๊ฒฝํํ Trouble Shooting์ ๊ณต์ ํด๋ณด๊ณ ์ ๊ธ์ ์์ฑํ๊ฒ ๋์์ต๋๋ค!
๋ค๋ค ๊ตฌ๊ธ ํผ, ๋ค์ด๋ฒ ํผ๊ณผ ๊ฐ์ ์๋น์ค๋ฅผ ๋ง์ด ์ด์ฉํด๋ณด์ จ์๊น์?
ํ์ฌ ์งํ ์ค์ธ ์บก์คํค ํ๋ก์ ํธ์์ ํ์๋ค์๊ฒ ํ์ฌ ์ฐธ์ฌ ์ ์ฒญ๋ฅผ ๋ฐ๊ธฐ ์ํ ํผ (์ค๋ฌธ) ์๋น์ค๋ฅผ ์ ๊ณตํ๊ธฐ ์ํด, ํผ ์์ฑ ํ์ด์ง๋ฅผ ์ง์ ๋ง๋ค๊ฒ ๋์๋๋ฐ์.
ํผ ์์ฑ ํ์ด์ง์์๋ ๋ง์ ์ด๋ฒคํธ๋ค(์ถ๊ฐ, ์ญ์ , ์์ ๋ฑ)์ด ์ด๋ฃจ์ด์ง๋ฏ๋ก, ์ด์ ๋ฐ๋ผ ์ฌ๋ฌ Input ์ปดํฌ๋ํธ๋ค์ ์ํ๋ฅผ ์ ๋ฐ์ดํธํด์ค์ผ ํด์ ์ ๊ฒฝ ์ธ ๋ถ๋ถ์ด ๋ง์ ํ์ด์ง๋ผ ๋ณผ ์ ์์ต๋๋ค. ํ์ ์คํฌ๋ฆฝํธ๊น์ง ์ด์ฉํ๋ค๋ฉด Type Guard๊น์ง ์ ๊ฒฝ์จ์ค์ผ ํ๋๋ฐ์๐ฅฒ
ํผ ์์ฑ ํ์ด์ง์์๋ useState๋ก ๊ด๋ฆฌ๋๋ questionList๋ฅผ ๋งตํํ์ฌ ์ง๋ฌธ ๋ฐ์ค ์ปดํฌ๋ํธ๋ค์ ๋ ๋๋งํฉ๋๋ค.
const [questionList, setQuestionList] = useState<Question[]>([]);
questionList๋ฅผ ๊ตฌ์ฑํ๋ Question์ ํ์ ์ ์๋์ ๊ฐ์ด ์ ์ํ์์ต๋๋ค.
type Question = {
type: QuestionType;
title: string;
description: string;
};
type QuestionType = 'SUBJECTIVE' | 'MULTIPLE'; // ์ฃผ๊ด์, ๊ฐ๊ด์
์ง๋ฌธ ๋ฐ์ค ์ปดํฌ๋ํธ๋ฅผ ๋ณด์๋ฉด ์ง๋ฌธ ์ ํ์ ์ ํํ๋ ์ฃผ๊ด์/๊ฐ๊ด์ ๋ฒํผ์ ๋ณผ ์ ์์ต๋๋ค. ์ด ๋ผ๋์ค input์ ํด๋ฆญ์ onChangeEvent ํธ๋ค๋ฌ๋ questionList[ํด๋น ์ธ๋ฑ์ค]์ type property๋ฅผ ์ ๋ฐ์ดํธํด์ผ ํ๋ฏ๋ก ๋ค์๊ณผ ๊ฐ์ด ์์ฑํ์์ต๋๋ค.
<input
className="hidden"
name={`question-type-${index}`}
type="radio"
value={questionList[index].type}
onChange={(e) => {
setQuestionList((prev) => {
return [
...prev.slice(0, index),
{ ...prev[index], type: e.target.value },
...prev.slice(index + 1),
];
});
}}
checked={questionList[index].tag === type}
/>
{icon}
</label>
Type '{ type: string; title: string; description: string; }' is not assignable to type 'Question'. Types of property 'type' are incompatible. Type 'string' is not assignable to type 'QuestionType'.
๊ทธ๋ฌ๋ onChange ์ด๋ฒคํธ ํธ๋ค๋ฌ์์ ํ์ ์ค๋ฅ๊ฐ ๋ฐ์ํ์์ต๋๋ค.
e.target.value์ ํ์ ์ด string์ด๋ฏ๋ก QuestionType๊ณผ ์ ํฉํ์ง ์๋ค๋ ์ค๋ฅ์ธ๋ฐ์.
์ปค์๋ฅผ ๋์ ํ์ธํด๋ณด๋ e.target.value๊ฐ string์ผ๋ก ์ง์ ๋์ด ์๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
๊ทธ๋ ๋ค๋ฉด value์ ๋ถ๋ชจ์ธ Change Event์ ํ์ ์ ์ง์ ์ง์ ํ ์ ์์๊น์?
๋ค! input์ ๊ธฐ๋ณธ ์์ฑ์ ์์ํ๊ณ Change Event๋ฅผ ์ค๋ฒ๋ผ์ด๋ฉํ๋ input ์ปดํฌ๋ํธ๋ฅผ ์ง์ ๋ง๋ ๋ค๋ฉด ๊ฐ๋ฅํฉ๋๋ค.
์ฐ์ Radio Input ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค๊ธฐ ์ ์ ์ปดํฌ๋ํธ props์ ํ์ ์ ์ ์ํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
props ํ์ ์ธ QuestionTypeButton์ Input ๊ธฐ๋ณธ ์์ฑ์ ์์๋ฐ๊ฒ ํ์๊ณ , onChange ์์ฑ์ event์ ์ง์ QuestionTypeButtonChangeEvent ํ์ ์ ๋ช ์ํ์ฌ ์ค๋ฒ๋ผ์ด๋ฉ๋๋๋ก ํ์์ต๋๋ค.
type QuestionTypeButton = HTMLAttributes<HTMLInputElement> & {
...์๋ต
value: QuestionType;
onChange: (e: QuestionTypeButtonChangeEvent) => void;
};
event์ ํ์ ์ธ QuestionTypeButtonChangeEvent๋ ๋ค์๊ณผ ๊ฐ์ด HTMLInputElement ChangeEvent์ ํ์ ์ ์์๋ฐ์ผ๋ฉฐ, target.value์ ํ์ ๋ง QuestionType์ผ๋ก ์ง์ ํ์ฌ ์ค๋ฒ๋ผ์ด๋ฉํ๋๋ก ํ์์ต๋๋ค. ๊ทธ๋ฌ๋ฉด event.target.value๋ string์ด ์๋ QuestionType์ผ๋ก ๋ช ์๋ฉ๋๋ค!
type QuestionTypeButtonChangeEvent = ChangeEvent<HTMLInputElement> & {
target: { value: QuestionType };
};
๊ทธ๋ ๊ฒ ๋ง๋ QuestionTypeButton ์ปดํฌ๋ํธ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
export type QuestionTypeButtonChangeEvent = ChangeEvent<HTMLInputElement> & {
target: { value: QuestionType };
};
type QuestionTypeButton = HTMLAttributes<HTMLInputElement> & {
...์๋ต
value: QuestionType;
onChange: (e: QuestionTypeButtonChangeEvent) => void;
};
export const QuestionTypeButton = ({
...์๋ต
value,
onChange,
...props
}: QuestionTypeButton) => {
return (
<label>
<input
...์๋ต
value={value}
onChange={onChange}
{...props}
/>
{icon} <span>{typeValue[value]}</span>
</label>
);
};
๋ง๋ QuestionTypeButton์ ์ฌ์ฉํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
์๋์ ๊ฐ์ด ์ฌ์ฉํ๋ฉด ๋ค์ ํ์ ์ค๋ฅ๋ฅผ ๋ค์ ๊ฒช๊ฒ ๋๋๋ฐ์.
<QuestionTypeButton
...์๋ต
index={index}
value={type}
onChange={(e) => {
setQuestionList((prev) => {
return [
...prev.slice(0, index),
{ ...prev[index], type: e.target.value },
...prev.slice(index + 1),
];
});
}}
/>
))}
event์ ํ์ ์ ํ์ธํด๋ณด๋ FormEvent์ ๊ฐ์ด ์ง์ ๋์ด์๋ ๊ฑธ ๋ณผ ์ ์์ต๋๋ค.
๊ทธ๋ฌ๋ฏ๋ก event์ ํ์ ์ ์์์ ์ ์ํ QuestionTypeButtonChangeEvent๋ก ๋ช ์ํ๋ค๋ฉด ํ์ ์ค๋ฅ๋ฅผ ํด๊ฒฐํ ์ ์์ต๋๋ค!
onChange={(e: QuestionTypeButtonChangeEvent) => { .... }
๊ทธ๋ ๊ฒ ๋๋ฉด ์ง๋ฌธ ์ ํ ์ ํ ๋ฒํผ์ ํด๋ฆญ์ questionList์ ์ํ ์๋ง๊ฒ ์ ๋ฐ์ดํธ๋๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค!