저번 시간에 컴포넌트 몇 가지를 추가하기 시작했습니다
그리고 여기 Quiz 컴포넌트에서
상태 몇 개를 관리하기 시작했습니다
이제 많은 양의 로직과
질문들이 필요합니다
그 전에 이 로직을 개선시킬 겁니다
제가 사용할 질문을 몇 개 드릴테니
그 질문들을 가지고 프로젝트를 진행하겠습니다
이 강의에 첨부된
질문 파일(questions.js)을 사용하시기 바랍니다
메인 파일(main.jsx) 바로 옆에 넣어
프로젝트에 추가해 주겠습니다
이 첨부된 파일을
메인 파일 다음에 삽입하고
그리고 그 질문 파일에
export문 아래에 있는 배열이 있는데
여기에 사용할 가짜 질문과
해당하는 답변이 모두 들어 있습니다
그리고 모든 질문에 ID가 부여되어 있는 것을 볼 수 있고
텍스트와 객관식 답변들도 있습니다
저 질문들에 대해 중요한 점은
항상 첫 번째 답변이 맞는 답이라는 겁니다
답변들을 유저에게 보여줄 때는
답변의 순서를 무작위로 섞어야 합니다
그렇게 하면 첫 번째 답이 항상
정답이 아닐 수 있습니다
그런데 여기 아직 처리되지 않은 데이터는
첫 번째 답변이 맞는 답변인데
이렇게 해야 웹 앱 로직에서 유저가 올바른 답을 골랐는지
판단할 수 있게 됩니다
이 로직은 조금 있다가 작업하겠습니다
여기 질문 배열이 있으니
Quiz 상태로 돌아가겠습니다
왜 이 상태 제어 방식이
최적의 방식이 아니라고 말씀드렸는데
왜 그렇게 말했을까요?
여기의 무엇이 잘못됐을까요?
지금은
두 개의 상태 snapshot (스냅샷)을 만들 계획입니다
즉 현재 활성화된 질문의 인덱스와
사용자가 선택한 답 배열입니다
이 적용 내용을 살펴 보시면
확인 가능한 것은
두 가지 상태 중 하나가
불필요하다는 점입니다
물론 사용자가 고른 답을
저장해야 하지만
활성화된 질문 인덱스의 경우
그것은 여기 이 userAnswers 배열에서
파생시켜 올 수(derive) 있습니다
여기서 각 질문마다 답변 하나를 보관할 것이기 때문입니다
그러므로 간단하게 이 배열에서
저장된 답변들의 숫자를 확인할 수 있습니다
그리고 활성화된 질문 인덱스가 되어야 하는 내용을
거기서 파생시켜올 수 있습니다
즉 해당 배열에 두 가지의 답변을 보관했다면
사용자는 이제 세 번째 질문을 받게 됩니다
첫 두 문제에 대한 답을
이미 받았기 때문입니다
그러므로 이 활성화된
질문 인덱스 상태를 삭제하고
대신에 가져온 상태를 추가합니다
이는 여기 컴포넌트로의 계산된값입니다
활성화된 질문 인덱스는 const (상수)가 되고
여기에서 사용자의 답변과
배열의 길이를 받습니다
만일 이 배열이 비어 있다면
이 부분은 0이 될 것이고
그리고 활성화된 질문 인덱스도 0이 될 것입니다
그래서 이것이 사용자에게
보여줄 첫 번째 질문이며
만일 하나의 답변이 추가되면
첫 번째 질문에 대한 답변이 이루어졌다는 뜻이기에
여기 인덱스 값은 1일 것이며
두 번째 질문이 이 질문 배열에 있을 겁니다
그리고 이것이 상태를 관리하는 더 나은 방식입니다
그 이유는 리액트에서
리액트 코드 작성 시
최소한의 상태를 가지고 있는 것이 좋습니다
대신 최대한 많은 상태를 파생해 오는 것이 좋습니다
여기서 한 작업이 그 내용입니다
그러므로 여기 우리 코드를 최적화 하는
이 변화를 가지고
드디어 사용자에게 질문을
제시할 차례입니다
여기 질문이 들어있는 배열을 가져와서
현재 활성화된 질문 인덱스와 함께
질문 내용을 화면에 출력하게 됩니다
그렇기에, 이 Quiz 컴포넌트에서
가짜 질문들을 가져오고
아직 처리되지 않은 가짜 데이터이므로
이름을 이렇게 짓고, 이 데이터를 import from을 이용해서
한 층위를 올라가서 질문 파일을 찾습니다
그리고 여기에 문단을 출력하는 대신
예를 들어 H2 태그를 출력할 수 있습니다
그리고 나서 questions를 내보내고
activeQuestionIndex를 이용해서 text 속성을 선택해 줍니다
이게 바로 화면에 표시될 질문의 속성입니다
또한 객관식 답안들도 아래에
내보내겠습니다
그런 다음 형식을 위해서 ID question을
div (디브)로 감싸겠습니다
제가 제공해드린
초기 프로젝트의 인덱스 파일(index.css)에
몇 가지 형식을 이미 설정을 해 두었습니다
question이라는 ID를 디브에 사용한다면
형식이 더 정리가 될 것입니다
그리고 H2 태그 아래에 순서 없는 목록을 내보내서
answers라는 ID를 사용하겠습니다
이 또한 형식을 위함입니다
그리고 여기에, 모든 객관식 답안을
내보내겠습니다
답의 순서가 무작위로 섞여야 하지만
그 설정은 조금 있다가 하겠습니다
지금은 일단 앱의 화면에서 확인하기 위해
activeQuestionIndex에 접근해서
답을 받아온 후에
이 목록을 매핑하겠습니다
그래서 여기 문자열 목록을
이전에 다룬 대로 JSX 컴포넌트로 매핑해 줍니다
이 함수에 answer을 받고
각 answer에
목록 항목을 내보내겠습니다
여기에서 각 목록 항목에 key (키)를 사용하되
키는 answer을 사용하겠습니다
이 답변은 모두 문자열이기 때문입니다
하지만 각각 다른 문자열입니다
각 답이 다른 텍스트라는 뜻입니다
즉 이것으로 적절한 식별자를 만들었습니다
그리고 모든 목록 항목에 answer의 클래스 이름을 부여합니다
이것 또한 형식을 위함입니다
그리고 나서 목록 항목 태그인 li 안에
버튼을 하나 내보내겠습니다
답변 선택을 위해서 클릭할 버튼입니다
이렇게
버튼 요소를 내보내고
버튼 태그 사이에는
답을 내보내겠습니다
이 답이 사용자들이 볼 답에 대한 텍스트입니다
이렇게 질문을 내보냈습니다
이제는 handleSelectAnswer라는 함수를
추가할 수 있습니다
이는 버튼이 눌렸을 때 작동하도록
설정되어 있습니다
이 버튼에
onClick 속성을 추가해 줘야 합니다
그리고 handleSelectAnswer로 가리켜 주면
이 함수가 실행됩니다
그리고 그 안에
userAnswers 배열 안의 선택된 답안을 보관하겠습니다
그리고 또한 당연하게도
이곳에 선택된 답안을값으로서 가집니다
즉 매개변수로 받습니다
userAnswers 상태 업데이트를 위함입니다
그러므로 이제
선택된 답안이
해당 함수에 닿을 수 있도록 하려면
이렇게 handleSelectAnswer에
가리키는 것만으로는 충분하지 않습니다
이렇게 하면 리액트는 호출만 하되
리액트는
선택된 답안을
다음 것으로 전달해야 한다는 것을 모릅니다
대신이 이것을 화살표 함수로
감싸주겠습니다
여기서는 몇 가지 다른 함수들을 감싸면
그 함수들은 리액트가 호출한 함수가 될 것입니다
그래서 이 잠재적으로 호출된 함수에 있는
handleSelectAnswer를
가져오는 방식에 대한 통제권을 더 갖게 됩니다
그리고 이제 얻게 된 답안을
handleSelectAnswer로 전달하면
여기 코드가 분석되고 나서 바로 실행되지 않습니다
대신에 버튼이 클릭 되었을 때만 실행됩니다
버튼이 눌려야 여기 바깥쪽 함수를 호출해 오기 때문입니다
그리고 거기서
커스텀 함수를 실행합니다
이렇게 작동이 되는데
이 강의에서 이미
여러 번 다룬 적이 있습니다
그렇지만 이 패턴에 대해 완전하게 숙지하고
이 패턴에 대해 이해하는 것이 중요합니다
그러므로, 여기 selectedAnswer를 받게 될 것이며
이제 답안에 따라 상태를 업데이트하게 됩니다
물론
이 상태는 배열이고
예전 답안들 또한 잃고 싶지 않습니다
다른 질문의 이전에 선택됐던
답안들에 대해서
함수 형식을 이용해서 이 상태를 업데이트 해줍니다
이는 상태 업데이트 함수에 함수를 전달합니다
왜냐하면 이 상태를 그 이전 버전에 따라
업데이트 해야 하고
이미 배우셨듯이 그럴 때마다
여기서 함수 형식을 사용해야 합니다
이제 여기에 prevUserAnswers를 가져오고
즉 그 상태의 기존 버전이자
가장 최신 버전으로 보장된 버전입니다
그러고 나서 업데이트된 상태를 반환합니다
새로운 배열이 될 것이고
이 곳에 현존하는 모든 사용자 답안들을 펼쳐둡니다
선택된 답안은 새로운 요소로
추가하겠습니다
그게 여기 상태가 업데이트 되어야 하는 방식이고
이전 상태를 잃지 않도록
그래서 증명된 가장 최신의 상태를 가지도록 하는 것입니다
그렇게 저 상태로 일단은 멈추고
앱 컴포넌트로 가겠습니다
이제 드디어 Quiz 컴포넌트를 가져오겠습니다
위치는 ./components quiz.jsx입니다
Header 출력 이외에도
Quiz를 내보내겠습니다
여기에 리액트의 빌트인 컴포넌트인 fragment를 사용하겠습니다
이를 이용해서 Header를 하나의 요소로서
그리고 Quiz를 또 다른 요소로서 받아올 수 있습니다
그래서 저들을 나란히 내보낼 수 있게 됩니다
그리고 또한 Quiz를
빌트인 main 요소로 감싸겠습니다
이렇게 구분하고 형식을 줄 수 있습니다
이제 모든 것을 추가했으니
저장을 하면
화면이 이렇게 보입니다
답과 질문이 잘 보입니다
하지만 형식이 조금 다르므로
퀴즈 파일(Quiz.jsx)로 가서
div (디브)를 사용해
question을 감싸겠습니다
그래서 이 질문 디브를 여기 또 다른 디브에 넣고
이 디브에 ID로 quiz를 넣어줍니다
이게 필요한 이유는, 나중에 퀴즈에 질문 말고도 더 많은
요소들을 추가해줄 것이기 때문입니다
그런데 여기 추가적인 둘러싸는 디브로
이제 이 모든 것들이 가운데에 정렬되어 있는 것을 보실 겁니다
멋진 테두리도 생겼고
답안들을 고를 수도 있고
질문에 대한 답안을 고르면서
퀴즈를 진행할 수 있습니다
그러나 언젠가는
질문 배열이 고갈될 것인데
그 때 에러가 발생해서 앱이 충돌합니다
이번 프로젝트에는 추가할 로직이 아주 많습니다
그 로직 중 하나에서 이 문제를 해결하겠습니다
어쨌든 일단은 질문들을 보여주고
답안들을 선택하는 부분은 아주 잘 작동합니다