개요
- 현재 진행 중인 토이 프로젝트의 Memory 파트는 암기노트를 컨셉으로 하고있다.
- 단순히 노트를 작성하는 것만 아니라, 암기를 위한 기능이 필요하다고 생각하여 무작위의 질문을 제시하되, 작성한 키워드와 본문을 선택하에 볼 수 있는 컴포넌트를 제작하였다.
- 그리고 간단하게 무작위 인덱스를 생성하여 해당하는 노트를 보여주는 로직으로 작성하였다.
→ 중복된 경우가 생김
- 최근 면접에서 프로젝트에 대해 주셨던 질문 중, 무작위 기능이 중복된 내용이 다시 표시되는 것에 대해 어떻게 생각하는 지에 대한 질문을 받았고, 기존 로직을 수정하여 개선해보기로 하였다.
기존 로직
function getRandomIdx(num: number) {
return Math.floor(Math.random() * num);
}
- num 이라는 매개변수에 노트의 총 갯수(배열의 길이) 를 전달하여 정수인 인덱스를 구하는 방식으로 작성하였다.
- 당연히 중복이 발생하는 경우가 생긴다.
- 표시되는 노트의 데이터를
currentQuestion
라는 상태에 저장하여 사용하고 있는데, 다음 질문 버튼을 누를 때 마다 아래의 갱신함수를 실행하여 무작위 인덱스의 위치에 있는 노트를 현재 질문으로 설정하는 방식으로 구현하였다.
<button
onClick={setCurrentQuestion(notesSlice[getRandomIdx(notesSlice.length)])}>
- 인덱스가 전적으로 무작위로 나오다 보니 동일한 질문이 연달아 나오거나 하는 경우가 발생하기도 했다.
개선 로직
- 작성된 노트의 인덱스를 가진 배열을 만들고, 해당 인덱스 배열을 뒤섞는 방식으로 진행해보기로 하였다.
- 이를 이용하면 인덱스 배열의 인덱스를 이동해가며 무작위 인덱스를 전달해 줄 수 있고, 총 질문이 몇개인지, 얼만큼 진행 했는지의 여부도 간단하게 표시해 줄 수 있었다.
무작위 인덱스 배열 만들기
- 일단 노트가 10개라고 가정했을 때, 0~9 까지의 값을 가진 인덱스 배열을 만들어야한다.
→ 그리고, 노트의 갯수에 따라 가변적이여야 했다.
- 그리고 해당 배열을 무작위로 순서로 정렬해야한다.
- 이를 종합하면 아래와 같다.
const getRandomIdxArr = (num: number) => {
const idxArr = Array(num)
.fill(null)
.map((el, idx) => idx);
return idxArr.sort(() => Math.random() - 0.5);
};
기능 구현
- 기존 로직의 경우
RandomNote
컴포넌트 내부에서 무작위 숫자를 생성하고, 인덱스에 접근하는 방식을 사용했지만, 개선 로직의 경우 상위 컴포넌트에서 인덱스 배열을 전달 해주어야 했다.
→ RandomNote
컴포넌트에서 생성시, 다음 버튼을 누를때마다 새로운 인덱스가 생성된다.
<RandomNote
idxArr={getRandomIdxArr(notesSlice.length)}
/>
- props 로 전달받은 인덱스 배열을
RandomNote
컴포넌트에서 currentQuestionIdx
상태를 이용하여 탐색하고, 초기값을 0으로 지정하여 상태갱신을 통해 증감하는 것으로 인덱스 배열 탐색을 구현했다.
- 이전에는 구현하지 않았던 이전 질문으로 이동하는 것도 쉽게 구현 할 수 있었다.
const [currentQuestionIdx, setCurrentQuestionIdx] = useState<number>(0);
const handleNextBtn = () => {
if (currentQuestionIdx < notesSlice.length - 1) {
setCurrentQuestionIdx(currentQuestionIdx + 1);
}
};
const handlePrevBtn = () => {
if (currentQuestionIdx > 0) {
setCurrentQuestionIdx(currentQuestionIdx - 1);
}
};
useEffect(() => {
setCurrentQuestion(notesSlice[idxArr[currentQuestionIdx]]);
}, [currentQuestionIdx]);
진행도 표시하기
- 위 처럼 로직을 수정함에 따라, 진행도를 아래와 같이 간단하게 표시 해 줄 수 있게 되었다.
<div className="indicator">
{currentQuestionIdx + 1} / {notesSlice.length}
</div>
결과