TestPage
TestPage에선 12문항을 제시한 뒤, 사용자가 선택한 선택지를 저장하여 MBTI를 결정해야했다.
*코드 드러움 주의*
import data from "../json/question";
12개의 문항을 보여주는데엔 하나하나 페이지를 만드는 방법도 있겠지만, 나는 이 12문항을 Json 데이터로 만들어서 가져오는 방법을 택했다.
사실 처음부터 Json 데이터로 하자! 했던 건 아니고, 이런 거 만들어 본 적 없던 코린이라, 구글링 하다가 다른 분 깃허브를 보고 이렇게 해야겠다 생각했다.
https://github.com/asroq1/Project_mbtiFeliz
감사합니다... 많은 도움이 됐습니다🥺
[
{
"id": 1,
"option": "EI",
"question1": "새 학년 새 학기 수업 시간. 이 수업에 팀플이 있다는 걸 알게 되었다. ",
"question2": "이 때 내가 든 생각은?",
"answers": [
{
"type": "E",
"content1": "'새로운 사람 만나는 건 좋지'",
"content2": "괜찮다고 생각한다"
},
{
"type": "I",
"content1": "'팀플 너무 싫어 드랍할 걸...'",
"content2": "벌써부터 힘들다고 생각한다"
}
]
},
...
]
이런 식으로 문항 12개를 만들었다. 쓸데없이 문항을 쪼개놓은 이유는, 문항의 2번째 줄은 bold 처리를 하고 싶어서 한 줄씩 쪼개서 저장했다.
그리고 import data from "../json/question"
이렇게 가져왔다.
let [searchParams, setSearchParams] = useSearchParams();
1) 각 문항마다 선택한 선택지를 저장하는 방법은 쿼리스트링을 이용했다. 매 문항마다 쿼리스트링을 업데이트 해주기 위해 useSearchParams 를 사용했다. 앞으로 선택지는 name=hyeon&res=IPISFJ
이런 식으로 이름 뒤에 res라는 key의 value형태로 저장될 것이다.
const [num, setNum] = useState(searchParams.get("res")?.length ?? 0);
2) 그리고 직접적으로 문항 번호를 저장하는 건 useState를 사용해 num 변수에 저장해줬다.
useEffect(() => {
const len = searchParams.get("res")?.length ?? 0
setMbti(searchParams.get("res")?.split('') ?? []);
if (len < 12)
setNum(searchParams.get("res")?.length ?? 0)
else {
navigate("/result?" + searchParams.toString());
}
}, [searchParams])
3) 맨 처음 0번째 문항을 렌더링 하기 위해서 useEffect를 사용했고, 다음 문항으로 넘어갈 때 문항에 따른 선택지를 보여주기 위해 배열에 searchParams를 넣었다.
3-1) seacrhParams.get("res")로 res뒤에 있는 쿼리스트링을 가져오고, length를 붙여 길이를 가져온다. 쿼리스트링의 값이 null일경우 (쿼리스트링 값이 없을 경우. 즉 0번째 문항일경우) 길이를 0으로 설정한다.
3-2) setMbti는 mbti 변수를 업데이트한다. mbti 변수는 선택한 mbti 요소를 저장한다. setMbti(searchParams.get("res")?.split('') ?? [])
역시 null일경우 빈배열로 한다. 고로 mbti의 초기값은 빈배열이다. null이 아닐경우 split으로 문자열을 배열로 변환하여 넣는다. 이제 searchParams가 업데이트될때마다 mbti가 줄줄이 소세지로 붙여질 것이다!
3-3) 문항은 총 12개. 길이가 12 미만일경우 아직 문항이 남아있다는 뜻으로 계속 setNum 해주고, 길이가 12가 될 경우 문항이 navigate로 resultPage로 이동함과 동시에 쿼리스트링의 값을 같이 보내줬다.
<div className="question">
<h1>Q{data[num].id}</h1>
<p>{data[num].question1}<br/>
<span>{data[num].question2}</span></p>
<button onClick={() => nextSlide(0)}>
{data[num].answers[0].content1}<br/>
<span>{data[num].answers[0].content2}</span>
</button>
<button onClick={() => nextSlide(1)}>
{data[num].answers[1].content1}<br/>
<span>{data[num].answers[1].content2}</span>
</button>
</div>
4) json의 값을 가져와서 해당 문항을 보여준다. num은 곧 쿼리스트링의 길이고 현재 문항이다.
const nextSlide = (i) => {
const a = [...mbti, data[num].answers[i].type]
setMbti(a);
searchParams.set("res", a.join(''))
setSearchParams(searchParams)
};
5) nextSlide는 선택한 문항의 숫자 (0 혹은 1)을 가져와 선택한 선택지 요소를 저장한다. const a에다가 기존 mbti값과 현재 선택한 값을 합친 배열을 넣어주고, setMbti를 해주면 현재 문항에서 선택한 mbti 요소가 mbti 변수에 합쳐진다. 그리고 searchParams.set을 통해 쿼리스트링에도 선택 요소를 반영한다.
set(name, value)
그리고 setSearchParams를 통해 쿼리스트링의 값을 업데이트 한다.
지금 보니 코드가 참 드럽다. 중복기능이 많이 들어간 것 같은데 3개월 전 코드라 수정하기가 넘 귀찮...다... 지금도 그렇지만 이걸 제작할 당시엔 진짜진짜 코린이어서, 친구도움도 받고 그렇다보니 중복기능이나 코드가 드럽다는 생각 자체를 못했던 것 같다. 홀홀