저번 시간에
Question 컴포넌트를 추가했고
키로 인한 문제들도 다 고쳤지만
또 새로운 문제가 추가적으로 생겼습니다
이제 많은 양의 속성을 전달해야 하기 때문입니다
이들은 올바르게 작동하는지 보기 위해
Quiz 컴포넌트에서
Question 컴포넌트로 관리되고 있습니다
그리고 이것은 우리가 좀 더 개선할 수 있는 사안입니다
그리고 동시에 Quiz 컴포넌트 또한 개선하겠습니다
예를 들어 모든 로직들에서
answerState를 관리하고 있는데
Quiz 컴포넌트에서 관리되어야 할 이유가 있을까요?
정답은 그럴 필요가 없다는 겁니다
이것이 끌어올릴 필요가 없는
상태에 대한 좋은 예시입니다
Question 컴포넌트로 가면
useSate 훅을 이용해서 새로운 상태를 추가합니다
이 또한 가져와야 하는데
이는 Question 컴포넌트에만 소속될 겁니다
그리고 이는 객체를 보관하는 상태가 될 수 있습니다
예를 들어 selectedAnswer
초기에 텅 빈 문자열을 가졌습니다
그러고 나서 isCorrect 속성을 넣어줍니다
초기 값은 null (널)입니다
그러나 True나 False 값을 가질 수도 있습니다
이것이 바로 이 곳에서 관리할 수 있는 상태입니다
answer라고 명명하겠습니다
그리고 setAnswer 상태 업데이트 함수를 가져옵니다
이제 단순하게 함수를 두고
답변이 여기서 선택될 때마다 작동되는
handleSelectAnswer를 가져옵니다
그래서 이 아래에서 handleSelectAnswer에 가리킵니다
그리고 여기에 answer 텍스트를 두고
setAnswer를 불러와서 이 객체를
새로운 객체로 설정하고 selectedAnswer를
여기 받게 되는 answer와 동격으로 설정합니다
그리고 isCorrect가 이제 파생되어야 합니다
그런데 이것은 1초 뒤에 파생되어야 합니다
이 1초는 이 Quiz 컴포넌트에서 보내는 1초입니다
현 상황으론, 널값으로 설정하겠습니다
이는 기본적으로 아직
정답인지 오답인지 모른다라고 하는 형식입니다
그러므로 여기에, setTimeout으로 timer를 설정합니다
1초 뒤에 isCorrect가 True값이 되거나 False값이 되도록 설정해줍니다
그래서 setAnswer를 다시 호출하면
이제 isCorrect를 동격으로 설정하고
이 설정값을 True로 설정하고
정답이라면 True 오답이라면 False입니다
그러나 그러기 위해선
어떤 것이 정답인지 알아야 합니다
이제 이 프로젝트의 장점은
질문과 답변을 이미 갖고 있다는 점입니다
이 questions.js (질문 파일)에 있으므로
이 파일을 다른 질문 파일(Questions.jsx)로 가져오겠습니다
현재의 질문을 확인해서
정답을 알아내기 위해서입니다
그래서 이 파일에 QUESTIONS를 가져와서
from을 선택하고 한 층위 올라가서 questions.js를 고릅니다
그래서 이제 질문들을 여기서 볼 수 있습니다
또한 좋은 점이
현재 활성화된 질문의 인덱스를 알 수 있습니다
왜냐하면 Quiz 컴포넌트에서 이 인덱스를
Question 컴포넌트의 키의 값으로서 설정할 것이기 때문입니다
그리고 우리는 그 키를
우리의 컴포넌트에 우리의 목적에 따라 사용할 겁니다
그래서 Question 컴포넌트에서
이 키 속성의 구조를 분해(destructure)하고 또한 여기에 사용할 수 있습니다
그래서 여기 timeout에
QUESTION를 키로서 접근합니다
그리고 특정한 질문을 살펴보기 위해
activeQuestionindex를 이용할 수 있습니다
그리고 여기서 첫 번째 답을 확인합니다
우리는 선택된 답이 정답이라는 것을
알고 있습니다
그리고 이를 우리의 답변과 비교합니다
그리고 이곳이 True로 나오면
정답이 선택되었다는 것을 알 수 있습니다
다른 경우라면 오답입니다
그걸 이용하여, 우리만의 answerState를
UI를 업데이트 하기 위해 쓸 수 있습니다
여기 answerState의값은
정답 아니면 오답이어야 합니다
그래서 여기에 도움이 될만한 변수를 추가하겠습니다
answerState라고 이름 짓고
이는 초기엔 텅 빈 문자열입니다
저의 예전 answerState가 Quiz 컴포넌트에 있었는데
그런데 만약 Question 컴포넌트의 answerState에서
selectedAnswer를 넣어주고
answer.isCorrect에 따라 answerState를 설정합니다
그리고 이게 True값이라면, correct로 설정하고 싶습니다
그게 아니면 wrong으로 설정합니다
그리고 나서 이 answerState는
answers로 전달될 것입니다
그런데 그것이 이제 answerState 속성과 충돌합니다
그러나 이 속성은 삭제되어야 합니다
더 이상 필요 없기 때문입니다
이제 onSelectAnswer는 삭제되지 않습니다
왜냐하면 아직 selectedAnswer를 Quiz 컴포넌트로
전달해야 하기 때문입니다
왜냐하면 Quiz 컴포넌트에
여전히 선택된 모든 userAnswer들을 보관해야 하기 때문입니다
퀴즈가 끝난 것인지 확인하기 위해서입니다
그러므로, onSelectAnswer를
여기 Timeout이 만료되고 사용자에게 고른 대답이
정답인지 아닌지를 보여줄 때 호출해줍니다
여기에 또다른 타이머를 설정해서
그래서 즉시 옮겨가지 않도록 하겠습니다
2초 후에 onSelectAnswer를 이 함수에 호출하고
selectedAnswer을 전달합니다
그리고 그러면 Quiz 컴포넌트에서
연결된 함수를 작동시킬 겁니다
그렇게 하면 여기 Question 컴포넌트에서 몇 가지 속성을
삭제할 수 있습니다
예를 들어, answers와 questionText와 같은 것들입니다
지금 미처리 데이터를 가져오기 때문이고
그리고 키가 activeQuestionIndex라는 걸 알기 때문입니다
그러므로 여기에 있는 속성을 삭제할 수 있고
대신에 키의 questions를 사용하면 됩니다
그러고 text는 왜냐하면 언급 했듯이 키이기 때문에
text는 activeQuestionIndex입니다
answer에 대해서는 QUESTIONS[key].answers를 써줍니다
이렇게 하면 두 개의 속성이 있어서 받아야 하는 수보다 적습니다
selectedAnswer 또한 더 이상 필요없습니다
왜냐하면 이제 Question 컴포넌트에 속하는
이 상태에 보관하기 때문입니다
이제 아래의 selectedAnswer를 업데이트 하기만 하면 됩니다
그리고 이것을 answer.selectedAnswer와 동격으로 설정합니다
해당 컴포넌트 상태에서
현재 관리되고 있는 selectedAnswer입니다
그렇게 하면, 이 Question 컴포넌트는
이제 더 많은 로직을 포함하고 더 많은 속성을 필요로 합니다
그러므로, Quiz 컴포넌트에서
그 모든 불필요한 속성들을 이제 삭제할 겁니다
정확하게 하기 위해, selectedAnswer, answerState
answers와 questionText가 대상이 됩니다
그리고 더 이상 필요 없는 로직을 모두 삭제해줍니다
특정적으로, answerState는 더 이상 필요없습니다
그리고 다시, activeQuestionIndex를
userAnswers.length에 기반하여 파생합니다
왜냐하면 이것은 이제
Qusetion 컴포넌트 안에서만 업데이트되기 때문입니다
답변을 기록하고 유저에게
정답인지 오답인지 2초 동안 보여주는 시점입니다
그리고 여기서 더 이상 answerState를 업데이트 할 필요가 없습니다
그리고 Quiz 컴포넌트에서
그 타이머들도 제거해야 합니다
그러므로, useCallback 쪽에
activeQuestionIndex도 더 이상 필요 없습니다
이를 가지고 Quiz 컴포넌트 함수는
더 간결해졌습니다
그리고 Question 컴포넌트는 더 강력해졌습니다
이제 전부 저장하고 보면
에러가 뜨는 것을 볼 수 있습니다
관리자 도구를 보면
키 속성을 사용하는데
여기 리액트에 의해서 독점적으로 사용되는 속성입니다
그리고 우리에 의해서 사용되어서는 안되는 것입니다
그러므로, 우리는 우리만의 속성을 골라야합니다
예를 들어, questionIndex 또는 그냥 index
아무 이름이나 고르시면 됩니다
그리고 이 속성을 키 대신 모든 상황에 사용해줍니다
Question 컴포넌트에서 사용한 키 대신에 넣겠습니다
그리고 Quiz 컴포넌트에서
인덱스 속성을 설정해야 합니다
키 속성과 같은 값을 가졌어도 동일합니다
그러나 리액트에 의해 예약된 속성이기 때문에
우리들만의 속성을 사용해야 합니다
그러나 이것으로 다시 불러온다면, 문제를 봅시다
문제를 로그할 수 있고
즉시 피드백을 얻을 수 있음을 알 수 있습니다
즉 질문에 대한 답이 올바른지 틀렸는지 알 수 있습니다
그리고 이제 질문 사이사이를
꽤 빠르게 이동합니다
이제 정답인지 오답인지를 즉시 표시하지 않도록 하기 위해
여기로 가야 합니다
Question 컴포넌트에서 answerState로 갑니다
correct 또는 wrong만 항상 설정하는 것이 아니라
대신에 answer.selectedAnswer이
True인지 확인하고 answer.isCorrect가 null과 동일하지 않도록 합니다
왜냐하면 만일 isCorrect가 널값이면
selectedAnswer를 가질지도 모른다는 것을 의미하고
결과를 아직 보여줄 수 없기 때문입니다
답변을 기록할 때
의도적으로 isCorrect를 널로 설정했기 때문입니다
이제 selectedAnswer를 선택된 대로
표시하도록 하기 위해, 그리고 또한
만일 이 조건이 들어맞지 않고
selectedAnswer를 가진다면
answerState를 answered와 일치하도록 설정하도록 합니다
여기 정답 파일에서 answer를 selected로
표시하기 위해 확인하는 조건입니다
이제 그 파일을 넣어서
모든 질문을 너무 빠르게 지나가지 않도록
조치를 취하겠습니다
여기에 만일
selectedAnswer가 있으면 답변 버튼을
클릭할 수 없도록 해서
그 후에 답변을 바꿀 수 없도록 하는 것입니다
그렇게 여기에 비활성화된 속성을 여기에 설정합니다
그리고 answerState가
빈 문자열인지에 따라 실행합니다
이는 아직 선택된 답변 없음이거나
다른 그 무엇도 일어나지 않은 상황입니다
만일 answerState가 빈 문자열과
일치하지 않는다면 해제될 것입니다
왜냐하면 이 빈 스트링이면 활성화되어야 하기 때문입니다
아직 답변이 없기 때문에 아직 비활성화되면 안 되는 것이죠
그러나 이것이 빈 문자열과 일치하지 않는다면
이것이 비활성화 되어야 한다는 것을 압니다
왜냐하면 우리는 정답과 오답을 가질 수 있는데
답변을 고르기만 했지 아직 모르기 때문입니다
이제 이대로 저장하고 새로고침을 하면
답변을 정할 수 있고 그러면 이 처럼 강조표시가 됩니다
다른 답변들은 흐려지고
정답인지 오답인지 표시됩니다
그 다음에는 다음 질문으로 잘 넘어갑니다