중요한 part
- 질문과 2개의 선택지 출력
- 선택지 하나 선택지 다음 질문으로 넘어감 + progressbar
- 마지막 질문지에서 선택지 선택 후에 결과페이지로 넘어가기
- 선택결과에 맞는 결과값 결과페이지에 출력
- 선택된 결과에 따른 결과값 필터링하는 알고리즘⭐⭐⭐⭐⭐
- 결과값 불러와 Result 컴포넌트에서 출력
⭐⭐⭐⭐⭐ mbti가 결정되는 과정⭐⭐⭐⭐⭐
{ id: "EI", score: 0 },
{ id: "SN", score: 0 },
{ id: "TF", score: 0 },
{ id: "JP", score: 0 },
QuestionData.js
id: 1,
title: '~~',
answera: 'E관련 답변',
answerb: 'I관련 답변',
type: 'EI',
},...
으로 이루어져있어 answera를 선택하게 되면 score에 +1, answerb를 선택하게 되면 score에 + 0
=> 마지막 결과에서 score가 2보다 크면 왼쪽이 선택되며 2보다 작을 시 오른쪽이 선택되면서 mbti가 결정됨.
const [questionNo, setQuestionNo] = useState(0);
const [totalScore, setTotalScore] = useState([
{ id: "EI", score: 0 },
{ id: "SN", score: 0 },
{ id: "TF", score: 0 },
{ id: "JP", score: 0 },
]);
const handleClickBtnA = (n, mbtiType) => {
if (mbtiType === "EI") {
const newTotalScore = { id: "EI", score: totalScore[0].score + n };
totalScore.splice(0, 1, newTotalScore);
} else if (mbtiType === "SN") {
const newTotalScore = { id: "SN", score: totalScore[1].score + n };
totalScore.splice(1, 1, newTotalScore);
} else if (mbtiType === "TF") {
const newTotalScore = { id: "TF", score:totalScore[2].score + n };
totalScore.splice(2, 1, newTotalScore);
} else {
const newTotalScore = { id: "JP", score: totalScore[3].score + n };
totalScore.splice(3, 1, newTotalScore);
}
setQuestionNo(questionNo + 1);
};
const handleClickBtnB = (n, mbtiType) => {
if (mbtiType === "EI") {
const newTotalScore = { id: "EI", score: totalScore[0].score + n };
totalScore.splice(0, 1, newTotalScore);
} else if (mbtiType === "SN") {
const newTotalScore = { id: "SN", score: totalScore[1].score + n };
totalScore.splice(1, 1, newTotalScore);
} else if (mbtiType === "TF") {
const newTotalScore = { id: "TF", score:totalScore[2].score + n };
totalScore.splice(2, 1, newTotalScore);
} else {
const newTotalScore = { id: "JP", score: totalScore[3].score + n };
totalScore.splice(3, 1, newTotalScore);
}
setQuestionNo(questionNo + 1);
};
splice() 메서드
splice(0,1,newTotalScore)
인덱스 0값부터 1개의 값 삭제 후 newTotalScore 추가
const handleClickBtnA = (n, mbtiType) => {
if (mbtiType === "EI") {
const updatedScore = totalScore.map((item) =>
item.id === "EI" ? { ...item, score: item.score + n } : item
);
setTotalScore(updatedScore);
} else if (mbtiType === "SN") {
const updatedScore = totalScore.map((item) =>
item.id === "SN" ? { ...item, score: item.score + n } : item
);
setTotalScore(updatedScore);
} else if (mbtiType === "TF") {
const updatedScore = totalScore.map((item) =>
item.id === "TF" ? { ...item, score: item.score + n } : item
);
setTotalScore(updatedScore);
} else {
const updatedScore = totalScore.map((item) =>
item.id === "JP" ? { ...item, score: item.score + n } : item
);
setTotalScore(updatedScore);
}
setQuestionNo(questionNo + 1);
};
const handleClickBtnB = (n, mbtiType) => {
if (mbtiType === "EI") {
const updatedScore = totalScore.map((item) =>
item.id === "EI" ? { ...item, score: item.score + n } : item
);
setTotalScore(updatedScore);
} else if (mbtiType === "SN") {
const updatedScore = totalScore.map((item) =>
item.id === "SN" ? { ...item, score: item.score + n } : item
);
setTotalScore(updatedScore);
} else if (mbtiType === "TF") {
const updatedScore = totalScore.map((item) =>
item.id === "TF" ? { ...item, score: item.score + n } : item
);
setTotalScore(updatedScore);
} else {
const updatedScore = totalScore.map((item) =>
item.id === "JP" ? { ...item, score: item.score + n } : item
);
setTotalScore(updatedScore);
}
setQuestionNo(questionNo + 1);
};
⇒ 위의 코드는 비효율성이 큼
const handleClickBtn = (n, mbtiType) => {
const newScore = totalScore.map((s) =>
s.id === type ? { id: s.id, score: s.score + n } : s
);
setTotalScore(newScore);
};
const handleClickBtn = (n, mbtiType) => {
const newScore = totalScore.map((s) =>
s.id === mbtiType ? { id: s.id, score: s.score + n } : s
);
setTotalScore(newScore);
if (QuestionData.length !== questionNo + 1) {
setQuestionNo(questionNo + 1);
} else {
navigate("/result");
}
};
<Button onClick={handleClickBtnA(1, QuestionData[questionNo].type)}>
{QuestionData[questionNo].answera}
</Button>
버튼을 클릭할 시 handleClickBtn이 작동하도록 함수를 집어넣었더니.. 에러가 발생했습니다..
그냥 아무생각없이 항상 하던대로 집어넣기만 했더니...
위와 같이 함수를 호출하면 클릭 이벤트를 등록하는 시점에서 함수가 즉시 실행되고, 클릭이 발생하기 전에 이미 실행된 함수의 결과가 전달되어 원하는 시점에 함수를 호출하지 않고 미리 실행하여 등록된 결과를 전달하게 되어 실제 클릭이 발생해도 함수가 실행되지 않는다고 한다...
따라서
<Button onClick={() => handleClickBtn(1, QuestionData[questionNo].type)}>
{QuestionData[questionNo].answera}
</Button>
와 같이 함수를 래핑해 전달해야 클릭이벤트가 발생할 때 함수가 실행되도록 할 수 있습니다.
-> 래핑을 사용하는 이유는 onclick 이벤트 핸들러에 함수를 전달하면서 매개변수를 전달해야했기 때문.
+) progressbar
const Count = () => {
return questionNo;
};
<progress value={Count()} max="12"></progress>
createSearchParams() : 검색 파라미터를 생성하는 함수
일반적으로 웹 어플리케이션에서 사용자가 검색 조건을 입력하고 해당 조건에 맞는 데이터를 검색하기 위해 URL의 쿼리 파라미터를 생성하는데 사용
reduce(acc, cur)
arr : 누산기, 최종적으로 출력되는 값
cur : 현재 돌고 있는 요소
substring(startindex, endindex)
: startindex부터 endindex이전까지의 값
Question.js
const mbti = newScore.reduce(
(acc, curr) =>
acc +
(curr.score >= 2 ? curr.id.substring(0, 1) : curr.id.substring(1, 2)),
""
);
navigate({
pathname: "/result",
search: `?${createSearchParams({
mbti: mbti,
})}`,
});
결과:
Result.js
const [searchParams] = useSearchParams();
const mbti = searchParams.get("mbti");
useSearchParams() : 쿼리스트링값 가져오는 hook
useSearchParams 훅을 사용하여 searchParams를 비구조화 할당으로 가져와 get메서드를 사용하여 'mbti'라는 쿼리 매개변수 값을 가져옴
const [resultData, setResultData] = useState([]);
useEffect(() => {
const result = ResultData.find((r) => r.best === mbti);
setResultData(result);
}, [mbti]);// 컴포넌트가 처음 랜더링 될 때 & mbti값이 변경될 때마다 실행되도록 설정
.
.
.
<Desc>{resultData.desc}</Desc>
splice() 메서드
splice(0,1,newTotalScore)
인덱스 0값부터 1개의 값 삭제 후 newTotalScore 추가
createSearchParams() : 검색 파라미터를 생성하는 함수
일반적으로 웹 어플리케이션에서 사용자가 검색 조건을 입력하고 해당 조건에 맞는 데이터를 검색하기 위해 URL의 쿼리 파라미터를 생성하는데 사용
reduce(acc, cur) 함수
arr : 누산기, 최종적으로 출력되는 값
cur : 현재 돌고 있는 요소
substring(startindex, endindex)
: startindex부터 endindex이전까지의 값
useSearchParams() : 쿼리스트링값 가져오는 hook