์ปดํฌ๋ํธ ๋ด๋ถ์์ router ์์ธ ์ฒ๋ฆฌ ํ๋ ์ฌ๋ฌ ๋ฐฉ๋ฒ
ํ์ฌ ๋ฉด์ ์ฐ์ต์๋น์ค์ธ Gomterview Git๋ฅผ ๊ฐ๋ฐ ์ค์ ๋๋ค. ์ด์ ์ ์ ํฌ์คํ ์ค ํ๋์ธ createBrowserRouter ๋ฅผ ํตํ ๋ผ์ฐํฐ ์ฒ๋ฆฌ์์ ํ์ธํ ์ ์๋ฏ, ์ ํฌ ์๋น์ค๋ createBrowserRouter๋ฅผ ํตํด์ router์ฒ๋ฆฌ๋ฅผ ์งํํ๊ณ ์์ต๋๋ค.
์ด๋ฒ ๊ธ์ ํด๋น createBrowserRouter๋ฅผ ํตํ ๋ก์ง์์ ๋ฐ์ํ ๋ฌธ์ ์ ์ด๋ฅผ ํด๊ฒฐํ ๋ฐฉ์์ ๋ด๊ณ ์์ต๋๋ค!
์ ํฌ ํ๋ก์ ํธ์์๋ ๋ค์๊ณผ ๊ฐ์ด CreateBrowserRouter ๊ธฐ๋ฐ์ router๋ฅผ ์ค์ ํด์ฃผ๊ธฐ ์ํด ๋ค์๊ณผ ๊ฐ์ ์ฝ๋๋ฅผ ์์ฑํด ์ฃผ์์์ต๋๋ค.
๋ค์๊ณผ ๊ฐ์ด path๋ก ์ง์
ํ๋ คํ๋ ๊ฒฝ์ฐ element์ <InterviewVideoPublicPage />
๋ก ์ด๋์ํค๋ฉฐ, loader๋ ํ์ด์ง์ ์ง์
ํ๊ธฐ ์ ํ์ํ ๋ฐ์ดํฐ๋ฅผ loadํ๊ณ , ์คํจํ๋ค๋ฉด redirect ์์ผ์ฃผ๊ธฐ ์ํด์ ์ฌ์ฉ๋์์ต๋๋ค.
์ ๋ ์ง๊ธ ์ฌ์ง๊ณผ ๊ฐ์ด InterviewViedoPublicLoader์์ useIsAllSuccess๋ผ๋ hooks๋ฅผ ์คํ์์ผ์ ํ์ฌ ์ ์ญ์ผ๋ก ์ค์ ํ recoil ์ํ๊ฐ์ ๋ฐํ์ผ๋ก setting์ด ๋ชจ๋ ์ ํด์ก๋ค๋ฉด, ํด๋น isAllSuccess์ ์ ๋ฌด์ ๋ฐ๋ผ์ ํ์ด์ง์ routing์ ์ค์ ํด ์ฃผ๋ ค ํ์ต๋๋ค.
ํ์ง๋ง ๋ค์๊ณผ ๊ฐ์ ์๋ฌ๊ฐ useIsAllSuccess์์ ๋ฐ์ํ์ต๋๋ค.
React Hook "useIsAllSuccess" is called in function "interviewVideoPublicLoader" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use".eslintreact-hooks/rules-of-hooks
ํด๋น ์๋ฌ๋ interviewVideoPublicLoader๋ผ๋ ํจ์๊ฐ React Router v6์ loader ํจ์ ๋ด์์ useIsAllSuccess๋ผ๋ React ํ ์ ํธ์ถํ๊ณ ์๋ค๋ฉด, ์ด๋ React์ ํ ์ฌ์ฉ ๊ท์น์ ์๋ฐํ๊ธฐ ๋๋ฌธ์ ๋ฐ์ํ ๋ฌธ์ ์์ต๋๋ค.
React Router์ loader ํจ์๋ React ์ปดํฌ๋ํธ๊ฐ ์๋๋ฏ๋ก, ์ด ์์์ React ํ ์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ด๋ React์ ๊ธฐ๋ณธ ๊ท์น ์ค ํ๋๋ก, ํ ์ ์ค์ง React ํจ์ ์ปดํฌ๋ํธ๋ ๋ค๋ฅธ ์ฌ์ฉ์ ์ ์ ํ ๋ด์์๋ง ํธ์ถ๋ ์ ์์ต๋๋ค.
ํจ์ํ ์ปดํฌ๋ํธ๋ user Custom Hooks ๋ด๋ถ ์์๋ง ํธ์ถ์ด ๊ฐ๋ฅํฉ๋๋ค. React ํ ์ ๋ฐ๋์ ํจ์ ์ปดํฌ๋ํธ๋ ์ฌ์ฉ์ ์ ์ ํ ๋ด์์๋ง ํธ์ถ๋์ด์ผ ํฉ๋๋ค. ์ผ๋ฐ ํจ์, ํด๋์ค ์ปดํฌ๋ํธ์ ๋ฉ์๋, ์ด๋ฒคํธ ํธ๋ค๋ฌ, ํ์ด๋จธ ์ฝ๋ฐฑ ๋ฑ์์๋ ํ ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์ ์๋์ ๊ฐ์ ๋ฐฉ๋ฒ์ ์ฌ์ฉํด์ผ ํ์ต๋๋ค.
์ฆ recoil ๊ธฐ๋ฐ์ hooks๋ฅผ ํตํด์ routing์ ์ฒ๋ฆฌํ๊ธฐ ์ํด์ ํ์ด์ง ๋ด๋ถ๋ก ์ด๋ํด์ ํด๊ฒฐํด์ผ ํฉ๋๋ค.
์ฐ๋ฆฌ๋ ์์์ ์ด๋ฐ ๊ฒฐ๋ก ์ ๋ด๋ฆด์ ์์์ต๋๋ค. "recoil ๊ธฐ๋ฐ์ hooks๋ฅผ ํตํ ํ์ด์ง ์์ธ์ฒ๋ฆฌ๋ createBrowserRouter์ ๊ฐ์ ์ธ๋ถ์์๋ ๋์์ด ๋ถ๊ฐํ๋ค. ์ฆ ํ์ด์ง ๋ด๋ถ์์ ํด๊ฒฐํด์ผํ๋ค." ๋ผ๋ ๊ฒฐ๋ก ์ ๋ด๋ ธ์ต๋๋ค. ์๋๋ ์ ๊ฐ ์์ธ์ฒ๋ฆฌ๋ฅผ ์งํํ๊ณ ์ถ์ Interview ๋ฅผ ์งํํ๋ InterviewPage ์ปดํฌ๋ํธ ์ ๋๋ค.
ํด๋น ์ปดํฌ๋ํธ๋ ๋ค์๊ณผ ๊ฐ์ด router ์ฒ๋ฆฌ๋ฅผ ์งํํ์ต๋๋ค.
const InterviewPage: React.FC = () => {
const { method } = useRecoilValue(recordSetting);
const { currentQuestion, getNextQuestion, isLastQuestion } =
useInterviewFlow();
const [stream, setStream] = useState<MediaStream | null>(null);
const [isRecording, setIsRecording] = useState(false);
const [isScriptInView, setIsScriptInView] = useState(true);
const [recordedBlobs, setRecordedBlobs] = useState<Blob[]>([]);
const [selectedMimeType, setSelectedMimeType] = useState('');
const [interviewIntroModalIsOpen, setInterviewIntroModalIsOpen] =
useState<boolean>(true);
// .... ๊ต์ฅํ ๋ง์ ๋น์ง๋์ค ๋ก์ง...
return (
<InterviewPageLayout>
<InterviewHeader
isRecording={isRecording}
intervieweeName={intervieweeName}
/>
<InterviewMain
mirrorVideoRef={mirrorVideoRef}
isScriptInView={isScriptInView}
question={currentQuestion.questionContent}
answer={currentQuestion.answerContent}
/>
// .... ๊ต์ฅํ ๋ง์ ์ปดํฌ๋ํธ ๋ค...
๋ค์๊ณผ ๊ฐ์ด ํ์ด์ง ์ปดํฌ๋ํธ๋ฅผ ๋ณด๋ฉด ์๋ง์ ๋น์ง๋์ค ๋ก์ง์ ๋ด๊ณ ์์ต๋๋ค. ํ์ง๋ง ์ด ํ์ด์ง์๋ ์ ์ ํ ๊ถํ์ ๊ฐ์ถ ์ ์ ๋ง์ด ์ ๊ทผํ ์ ์์ด์ผ ํฉ๋๋ค.
๊ทธ๋์ ๊ตฌํํ ๋ฐฉ์์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค! ์ ๊ฐ ์๊ฐํ ๋ก์ง์ ํ์ด์ง ์๋จ์์ isAllSuccess๋ผ๋ boolean ์์๋ก ์ธํด์ ํ์ด์ง์ ๋ผ์ฐํ ์ ๊ฒฐ์ ํ๋ ๊ฒ์ด์์ต๋๋ค. ํ์ง๋ง ์ด๋ ๋ค์๊ณผ ๊ฐ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๊ฒ๋ฉ๋๋ค. ์ด ๊ฒฝ๊ณ ๋ฉ์ธ์ง๋ navigate ํจ์๋ฅผ useEffect์ธ๋ถ์์ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ๋ฐ์ํ ๋ฌธ์ ์ ๋๋ค.
React ์ปดํฌ๋ํธ๋ ์ฌ๋ฌ ๋ผ์ดํ์ฌ์ดํด ๋จ๊ณ๋ฅผ ๊ฑฐ์น๋ฉฐ ๋ ๋๋ง๋ฉ๋๋ค. ์ด๊ธฐ ๋ ๋๋ง ์์๋ ์ปดํฌ๋ํธ๊ฐ DOM์ ์ฒ์์ผ๋ก ๋ง์ดํธ๋๋ ๋จ๊ณ์ ๋๋ค. ์ด ๋จ๊ณ์์ ์ฌ์ด๋ ์ดํํธ(์: ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ, ํ์ด๋จธ ์ค์ , ๋ค๋น๊ฒ์ด์ ๋ฑ)๋ฅผ ์คํํ๋ฉด ์์์น ๋ชปํ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค. useEffect ํ ์ ์ปดํฌ๋ํธ ๋ ๋๋ง ์ดํ์ ์ฌ์ด๋ ์ดํํธ๋ฅผ ์ํํ๊ธฐ ์ํ React์ ๋ฐฉ๋ฒ์ ๋๋ค. useEffect ์ฌ์ฉํ๋ฉด React๊ฐ DOM ์ ๋ฐ์ดํธ๋ฅผ ์๋ฃํ ํ์ ์ฌ์ด๋ ์ดํํธ๋ฅผ ์์ ํ๊ฒ ์คํํ ์ ์์ต๋๋ค.
์ปดํฌ๋ํธ๊ฐ ์ฒ์ ๋ ๋๋ง๋ ๋ navigate()๋ฅผ ์ง์ ํธ์ถํ๋ฉด, ๋ ๋๋ง ๊ณผ์ ์ด ์์ ํ ๋๋๊ธฐ ์ ์ ํ์ด์ง ๋ค๋น๊ฒ์ด์ ์ด ๋ฐ์ํ ์ ์์ต๋๋ค. ์ด๋ ๋ ๋๋ง ์ฌ์ดํด์ ๋ฐฉํดํ๊ณ , ์์์น ๋ชปํ ๋ ๋๋ง ์ด์๋ ๋ฒ๊ทธ๋ฅผ ์ด๋ํ ์ ์์ต๋๋ค. useEffect ๋ด์์ navigate()๋ฅผ ํธ์ถํ๋ฉด, ์ปดํฌ๋ํธ๊ฐ ํ๋ฉด์ ์์ ํ ๋ง์ดํธ๋ ํ์ ๋ค๋น๊ฒ์ด์ ์ด ์ด๋ฃจ์ด์ง๋๋ค. ์ด๋ ๋ ์์ ์ผ ์ ์์ผ๋ฉฐ, ๋ ๋๋ง React์ ๋ ๋๋ง ์ฌ์ดํด์ side effect๋ฅผ ๋ถ๊ณผํ์ง ์์ต๋๋ค.
๋ฐ๋ผ์ ๋ค์๊ณผ ๊ฐ์ด ์์ ํ ์ ์์ต๋๋ค!
๋ค์๊ณผ ๊ฐ์ด ์์ ํ๋ฉด, ์์ ๊ฐ์ ๊ฒฝ๊ณ ๊ฐ ์ฌ๋ผ์ง๊ฒ ๋ฉ๋๋ค.
ํ์ง๋ง ์ฌ๊ธฐ๊น์ง ์งํํด๋ณด๋ฉด ์ด์ง ์ ๊ฒฝ ์ฐ์ด๋ ์ ์ด ์์ต๋๋ค.
์ปดํฌ๋ํธ๊ฐ ํ๋ฉด์ ์์ ํ ๋ง์ดํธ๋ ํ์ ๋ค๋น๊ฒ์ด์ ์ด ์ด๋ฃจ์ด์ง๋๋ค.
๊ทธ๋ ๋ค๋ฉด ํ์ ์ปดํฌ๋ํธ๊ฐ ๋ฌด์ํ ๋ง๋ค๋ฉด...?
**๊ทธ ๋ฌด์ํ ๋ง์ ์ปดํฌ๋ํธ์ ๋ ๋๋ง์ด ๋ชจ๋ ๋ง์น ํ์์ผ navigate๊ฐ ๋์ํ๊ฒ ๋๋ค๋ฉด, ์ด๋ ํฌ๋ํฐ ๋ฌธ์ ๋ฅผ ์ผ์ผํฌ ์๋ ์์ต๋๋ค. **
๋ฌผ๋ก UI ์์์ ๋ง๋ ๋ฐฉ๋ฒ๋ ์์ผ๋ User๊ฐ ์ง์ url์ ์ ๋ ฅํ ๊ฒฝ์ฐ์๋ ๋์ฒํ์ง ๋ชปํฉ๋๋ค. (์ฌ์ค ์ด๋ฅผ ๊ทน๋ณตํ๊ธฐ ์ํด createBrowserRouter์ loader ๋ฅผ ์ฌ์ฉํ๋ ค ํ์ต๋๋ค.)
๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ๊ฐ์ฅ ์ ์ ๋น์ฉ์ผ๋ก ์ต์ ํ๊ฐ ํ์ํ์ต๋๋ค.
์ฌ์ค ์์ฃผ ๊ฐ๋จํ ํด๊ฒฐ์ฑ ์ด ์์์ต๋๋ค. React Router์์ ์ ๊ณตํ๋ Navigate ์ปดํฌ๋ํธ๋ ์ด๋ฌํ ์ํฉ์ ์ ํฉํ ํด๊ฒฐ์ฑ ์ ์ ๊ณตํฉ๋๋ค. Navigate ์ปดํฌ๋ํธ๋ JSX ๋ด์์ ์กฐ๊ฑด๋ถ ๋ ๋๋ง์ ํตํด ์ฌ์ฉ๋ฉ๋๋ค. ์ด๋ useEffect์ navigate ํจ์๋ฅผ ์ฌ์ฉํ๋ ๊ฒ๋ณด๋ค ์ ์ธ์ ์ด๊ณ ์ง๊ด์ ์ธ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค!
๋ฌด์๋ณด๋ค InterviewPageLayout์ ํด๋นํ๋ ์ปดํฌ๋ํธ๋ค์ ๋ชจ๋ ๋ ๋๋ง ํ์ง ์๋๋ค๋ ์ ์ ๊ฝค๋ ๋งค๋ ฅ์ ์ ๋๋ค.
์ฌ์ค ์ฌ๊ธฐ๊น์ง ์ ์ฝ์ผ์ จ๋ค๋ฉด, ์์ง ๋ฌธ์ ๊ฐ ์๋ค๋ ์ ์ ์ ๋ง ์ฝ๊ฒ ๋์น ์ฑ์ค ์ ์์ต๋๋ค. ์ด๋ ๊ฒ ํจ์ํ ์ปดํฌ๋ํธ์ ํ๋จ์ return ๊ตฌ๋ฌธ์์ Navigate๋ฅผ ๋ฐํํ๊ฒ ๋๋ค๋ฉด, ์๋์ ์ปดํฌ๋ํธ๋ค์ ๋ฐํํ๊ธฐ ์ ์ Navigate ๊ฐ ๋์ํ๊ฒ ๋์ง๋ง, ํด๋น ์ปดํฌ๋ํธ์ ๋ชจ๋ ๋น์ง๋์ค ๋ก์ง์ด ๋์ํ๊ฒ ๋ฉ๋๋ค.
๊ทธ๋ ๋ค๊ณ ์ด๋ฅผ ๋ง๊ธฐ ์ํด์ ์ต์๋จ์์ Navigate๋ฅผ ๋ฐํํด ๋ฒ๋ฆฐ๋ค๋ฉด, rule of hooks ๋ผ๋ ๊ฒฝ๊ณ ๊ฑธ๋ฆฌ๊ฒ ๋ฉ๋๋ค. ํด๋น ๊ฒฝ๊ณ ๋ hooks๊ฐ ํธ์ถ๋๋ ์์ ์ ๋ํ ๊ท์น์ ์๋ฏธํ๋๋ฐ, ์ฌ๊ธฐ์๋ ์๋จ์ Navigate๋ฅผ ๋ฐํํด ๋น์ง๋์ค ๋ก์ง ๋ถ๋ถ์ hooks๊ฐ ํธ์ถ์ด ๋์ง ์์ ์ ์์ด ๋ฐ์ํ๋ ๊ฒฝ๊ณ ์ ๋๋ค.
๋ฐ๋ผ์ ์๋ฒฝํ์ง ์์ง๋ง ์ ์ ๋น์ฉ์ผ๋ก ์์ง ์์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐ ๊ทผ์ฒ๊น์ง ๋๋ฌํ๋ฏํฉ๋๋ค.