💣 중복 세션 생성 문제
위는 기술 면접(문제풀기, 채점하기)를 한 싸이클로 만들어 저장하기 위한 테이블이다.
const { data: sessionData, error: sessionError } = await supabase
.from('tech_sessions')
.insert({ user_uuid: userUid })
.select()
.single();
위 코드는 tech_interview > page.tsx 에서 처음 기술 면접 페이지에 접근했을 때, 세션 테이블을 생성하는 로직이고
위 로직은 useEffect안에서 이루어진다. 또한 useEffect에 의존성은 로그인 한 유저의 useId를 의존성배열에 넣었다.
의도대로라면 한번에 한개의 세션ID만 생겨야 하는데 서로 다른 ID의 세션이 두개씩 생기는 이슈가 있었다.
원인은 strict mode인것 같았다.
strict mode는 자바스크립트 언어의 문법을 보다 엄격히 적용하여 기존에는 무시되던 오류를 발생시킬 가능성이 높거나 자바스크립트 엔진의 최적화 작업에 문제를 일으킬 수 있는 코드에 대해 명시적인 에러를 발생시킨다.
reactStrictMode: false,
next.config 파일에서 위 코드를 추가하여 해결을 할 수 있었지만 좋은 방법은 아니라고 생각했다.
그래서 useRef를 사용하여 sessionCreated.current이라는 플래그를 만들고, 이 플래그로 세션이 한 번만 생성되도록 관리했다.
1. useRef로 플래그 생성
const sessionCreated = useRef(false); // 세션이 한 번만 생성되도록 관리
2. useEffect 내에서 플래그 확인
useEffect(() => {
const initializeTest = async () => {
// 세션이 이미 생성되었는지 확인
if (sessionCreated.current) return; // 세션이 이미 생성되었으면 더 이상 생성하지 않음
sessionCreated.current = true; // 세션을 생성한 후 플래그를 true로 설정
// 세션 생성 로직 (비동기 호출)
const { data: sessionData, error: sessionError } = await supabase
.from('tech_sessions')
.insert({ user_uuid: userUid })
.select()
.single();
if (sessionError) {
console.error('세션 생성 중 오류가 발생했습니다:', sessionError);
setLoading(false);
return;
}
setSessionId(sessionData.tech_session_id); // 세션 ID 저장
setLoading(false);
};
initializeTest();
}, [userUid]); // userUid가 변할 때만 useEffect 호출
위와 같이 코드를 수정하니 세션이 한번에 한번만 생성되었고 내 의도대로 동작하는 코드가 되었다.
💣 채점 타입 오류 및 상태 초기화 문제
잘못된 코드 :
const [gradedResponses, setGradedResponses] = useState<{ [key: string]: boolean | null }>({});
이 코드는 상태 초기화를 빈 객체로 시작하지만, 이후 상태에 접근할 때, gradedResponses의 각 키에 대한 기본 값이 설정되지 않아서 undefined 상태로 접근하고 이후 상태를 사용할 때, 타입 오류가 일어났다.
문제 :
상태가 {}로 초기화되었으나, 각 질문에 대해 tech_question_id에 대응하는 값이 없으면 undefined로 상태에 접근한다.
이로 인해 타입 오류나 로직 오류가 발생하였다.
( gradedResponses[questionId]에 boolean | null 타입이 아닌 undefined가 반환됨)
해결방안 :
상태를 초기화할 때, 미리 각 tech_question_id에 대해 기본 값으로 null을 설정해야한다.
이를 통해 gradedResponses[questionId]가 항상 null 또는 boolean 값만 반환되도록 하여 오류를 방지한다.
수정된 코드 :
// 사용자 답변과 기술문제를 묶어 객체로 정리
const mappedResponses = responseList.map((response) => {
const question = questionList.find((q) => q.tech_question_id === response.tech_question_id); // 해당 기술문제를 찾기
return {
...response,
tech_question_text: question?.tech_question_text,
tech_question_answer: question?.tech_question_answer
};
});
setResponses(mappedResponses);
// 각 기술질문의 tech_question_id가 키로 사용
// true는 사용자가 o 버튼 눌렀을 때, false는 사용자가 x 버튼 눌렀을 때, null은 채점 안했을 때
// 처음은 비어있는 객체
const initialGrad: Record<string, boolean | null> = {};
// mappedResponses를 반복하며 각 기술질문의 tech_question_id를 키로 하고, 값을 null로 설정
mappedResponses.forEach((response) => {
initialGrad[response.tech_question_id] = null;
});
setGradedResponses(initialGrad);
questions 배열을 반복하여, 각 질문의 tech_question_id를 키로 설정하고 기본값으로 null을 할당한다.
그런 다음, useState를 사용하여 상태 초기화 시 빈 객체 대신 기본 상태로 시작한다.
'팀프로젝트' 카테고리의 다른 글
hobeet 프로젝트 - 기획2 (0) | 2024.10.23 |
---|---|
hobeet 프로젝트 - 기획1 (0) | 2024.10.23 |
가취뽀 프로젝트 - 1 (2) | 2024.10.10 |
food compass 프로젝트 - 최종 (7) | 2024.09.23 |
food compass 프로젝트 트러블 슈팅 (0) | 2024.09.20 |