- React
- React-router
- useState, useEffect, useNavigate, useSearchParams
- CSS module, Sass
react: "^18.2.0",
react-router-dom: "^6.4.3",
sass: "^1.56.1",
sass-loader: "^13.2.0"
- 🔗netlify
- 네이버 웹 마스터 도구
- GitHub
- GitHub-Wiki
📦
├─ public
│ ├─ _redirects
│ ├─ favicon.svg
│ ├─ index.html
│ ├─ robots.txt
│ └─ sitemap.xml
└─ src
│ ├─ App.js
│ ├─ index.js
│ ├─ assets
│ │ ├─ data
│ │ │ ├─ questionData.js
│ │ │ └─ resultData.js
│ │ ├─ svg
│ │ └─ typeImage
│ ├─ components
│ │ ├─ common
│ │ │ ├─ Button.jsx
│ │ │ └─ Wrapper.jsx
│ │ ├─ guage
│ │ │ ├─ Guage.jsx
│ │ │ └─ GuageHeart.jsx
│ │ ├─ match
│ │ │ ├─ Match.jsx
│ │ │ └─ MatchBox.jsx
│ │ ├─ resultDesc
│ │ │ ├─ ResultDesc.jsx
│ │ │ └─ ResultList.jsx
│ │ └─ shareButton
│ │ ├─ FacebookShareButton.jsx
│ │ ├─ KakaoShareButton.jsx
│ │ ├─ ShareButton.jsx
│ │ └─ TwitterShareButton.jsx
│ ├─ page
│ │ ├─ AllResultPage.jsx
│ │ ├─ HomePage.jsx
│ │ ├─ QuestionPage.jsx
│ │ └─ ResultPage.jsx
│ └─ style
│ ├─ commonStyle
│ │ ├─ Button.module.scss
│ │ ├─ Wrapper.module.scss
│ │ ├─ _utils.scss
│ │ └─ reset.css
│ ├─ guageStyle
│ │ ├─ Guage.module.scss
│ │ └─ GuageHeart.module.scss
│ ├─ matchStyle
│ │ ├─ Match.module.scss
│ │ └─ MatchBox.module.scss
│ ├─ pagesStyle
│ │ ├─ AllResultPage.module.scss
│ │ ├─ HomePage.module.scss
│ │ ├─ QuestionPage.module.scss
│ │ └─ ResultPage.module.scss
│ ├─ resultDescStyle
│ │ ├─ ResultDesc.module.scss
│ │ └─ ResultList.module.scss
│ └─ shareButtonStyle
│ └─ ShareButton.module.scss
├─ netlify.toml
├─ package-lock.json
└─ package.json
©generated by Project Tree Generator
홈페이지 | 질문 페이지 | 결과 페이지 |
---|---|---|
![]() |
![]() |
![]() |
시작하기 버튼 클릭하면 질문 페이지로 navigate | 한 답안을 클릭하면 다음 질문페이지로 navigate | 12문제 전부 답을 고르면 유형 페이지로 navigate |
궁합 및 유형 설명 | 질투 유형 순위 페이지 | SNS 공유 |
---|---|---|
![]() |
![]() |
![]() |
궁합 이미지 클릭하면 해당 유형으로 navigate | 유형 이미지 클릭하면 해당 유형으로 navigate | SNS 공유 버튼 누르면 테스트 결과 페이지 공유 |
const [totalScore, setTotalScore] = useState([
{ id: "EI", score: 0 },
{ id: "SN", score: 0 },
{ id: "TF", score: 0 },
{ id: "JP", score: 0 },
]);
const newScore = totalScore.map((s) =>
s.id === type ? { id: s.id, score: s.score + n } : s);
setTotalScore(newScore);
-
QuestionData. js의 type과 QuestionPage.js의 totalscore useState의 id가 일치할 때 score에 점수를 추가한다.
-
일치하지 않으면 state의 기존 객체를 유지한다.
11번 문제까진 다음 문제로 문제수 증가
if (QuestionData.length !== questionNum + 1) {
setQuestionNum(questionNum + 1);
} else {
//mbti 도출
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 })}`,
});
}
-
문항 수 11번까지 증가시키기
questionNum이 QuestionData.js의 길이와 일치하지 않을 때 questionNum을 1씩 증가시켜준다.
-
12번 문항에서 mbit 도출하기
문항별 점수(score) 저장된 newScore 배열을 돌면서 점수가 2보다 크거나 같으면 앞의 알파벳을, 작으면 뒤의 알파벳을 acc에 저장한다. 그리고 직전에 동작한 콜백 함수가 리턴한 값을 acc에 전부 모아 mbti 유형을 완성한다.
-
결과 페이지로 이동
URL의 result 경로(path) 뒤에 붙는 쿼리(query)를 설정.
/result?mbti=ENFP
형태의 URL로 나온다.
const navigate = useNavigate();
const [searchParams] = useSearchParams();
const mbti = searchParams.get("mbti");
const [resultData, setResultData] = useState({});
useEffect(() => {
const result = ResultData.find((s) => s.type === mbti);
setResultData(result);
}, [mbti]);
- QuestionData의 mbti query를 가져오고, mbti가 바뀔 때마다 바뀐 mbti와 일치하는 ResultData의 type을 찾아서 해당 데이터를 가져온다.
참고 GitHub: https://github.com/ggombee/catmbti