16일차에 찾은 오류를 오늘 본격적으로 수정할 것이다!
어떻게 해야할지는 대략적으로 감이 잡히긴 하지만 경로를의 깊이를 어떻게 잡을 것이냐, 같은 경로의 컴포넌트 여러개를 어떻게 처리할 것이냐에 대한 고민을 하고 있다.
어찌저찌 고치니까 2개 뜨던 오류가 하나만 뜬다.
왜 하나만 뜨지? 왜 하나는 없어졌을까?
function App() {
return (
<BrowserRouter>
<GlobalStyles />
<Header category={<Nav01 />} logout={<Nav02 />} login={<Nav03 />} />
<Routes>
<Route path="/" element={<Banner01 />} />
<Route path="/explore/*" element={<ExploreBanner />}/>
<Route path="/community/*" element={<CommunityBanner />} />
<Route path="/point" element={<PointBanner />} />
<Route path="/qna" element={<QnaBanner />} />
<Route path="/mypage/*" element={<MypageBanner />} />
</Routes>
<Body>
<Routes>
{/* <Route path="/explore/*" element={<Aside01 />} /> */}
{/* <Route path="/mypage/*" element={<Aside02 />} /> */}
</Routes>
<Routes>
{/* <Route path="/" element={<Main category={<A />} top={<B />} banner={<Banner02 />} />} /> */}
<Route path="/explore/cafe" element={<Cafe />} />
<Route path="/signIn" element={<SignIn />} />
<Route path="/signUp" element={<SignUp />} />
</Routes>
</Body>
<Footer />
</BrowserRouter>
);
}
이런식으로 여러개의 Routes를 사용하고 있었을 때, 어떤 Route 안에는 "/" 경로가 있고, 어떤 Route안에는 "/" 경로가 없어서 오류가 나는 것이다.
그래서 Routes를 하나만 사용하고 Route를 중첩해서 중첩된 Route는 Outlet으로 불러올 수 있다는 의미였다.
그러니까 머릿속으로는 진작에 이해를 했는데 그걸 내 코드에 어떻게 적용을 시키라는거지 ????? 싶은 의문이 가득 했었다 😭😭😭
나는 한 페이지에 배너도 보여줘야하고 사이드바랑 바디랑 다 보여줘야하는 페이지가 있단말이야..!!! 레이아웃이 같을 수 없다구..
그래? 그러면 레이아웃 컴포넌트를 만들면 되지 😎
function App() {
return (
<BrowserRouter>
<GlobalStyles />
<Header category={<Nav01 />} logout={<Nav02 />} login={<Nav03 />} />
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<MainBanner />} />
<Route path="community/*" element={<CommunityBanner />} />
<Route path="point" element={<PointBanner />} />
<Route path="qna" element={<QnaBanner />} />
<Route path="signIn" element={<SignIn />} />
<Route path="signUp" element={<SignUp />} />
</Route>
<Route path="explore/*" element={<ExploreLayout />}>
<Route path="cafe" element={<Cafe />} />
<Route path="entertainment" element={<Cafe />} />
<Route path="culture" element={<Cafe />} />
</Route>
<Route path="mypage/*" element={<MypageLayout />}>
<Route index element={<Cafe />} />
</Route>
</Routes>
<Footer />
</BrowserRouter>
);
}
Routes와 Route는 이렇게 합쳐주었다.
import { Outlet } from 'react-router-dom';
const Layout = () => {
return(
<Outlet />
)
}
export default Layout;
import { Outlet } from 'react-router-dom';
import styled from 'styled-components';
import { MypageBanner } from './banner/Banner03';
import Aside02 from './aside/Aside02';
const Body = styled.div`
display: flex;
justify-content: center;
`
const MypageLayout = () => {
return(
<>
<MypageBanner />
<Body>
<Aside02 />
<Outlet />
</Body>
</>
)
}
export default MypageLayout;
import { Outlet } from 'react-router-dom';
import styled from 'styled-components';
import { ExploreBanner } from './banner/Banner03';
import Aside01 from './aside/Aside01';
const Body = styled.div`
display: flex;
justify-content: center;
`
const ExploreLayout = () => {
return(
<>
<ExploreBanner />
<Body>
<Aside01 />
<Outlet />
</Body>
</>
)
}
export default ExploreLayout;
그리고 레이아웃 컴포넌트들.
깨끗한 나의 콘솔창 ㅠ_ㅠ 해결해서 다행이다..
이렇게 Outlet에 대해서 배웠다.
I Love Google
<div className="signUp">
<form className="signUp-wrapper">
<Logo height="55" role="img"/>
<div className="signUp__auth">
<Input01 type={"text"} placeholder={"이메일"} size={"s"} onChange={onChangeInputs("email")} required disabled={Inputs.disabled}
pattern={emailPattern} title={"ex) naru@naru.com"} onInvalid={onInvalid("사용할 수 없는 이메일입니다.")} onInput={onInput}/>
<Button01 type="button" text={"인증메일 발송"} size={"m"} onClick={onClickEmail} />
</div>
<div className="signUp__auth">
<Input01 type={"number"} placeholder={"인증번호"} size={"s"} onChange={onChangeInputs("authNum")}
onInput={authMaxLength} maxLength={6}/>
<Button01 type={"button"} text={"인증번호 확인"} size={"m"} onClick={onClickAuth} />
</div>
<Input01 type={"text"} placeholder={"닉네임 (한글,영문,숫자 포함 2~8자)"} size={"m"} onChange={onChangeInputs("nickname")} required
pattern={nicknamePattern} title={"한글,영문,숫자 포함 2~8자"} onInvalid={onInvalid('사용할 수 없는 닉네임입니다.')} onInput={onInput}/>
<Input01 type={"password"} placeholder={"비밀번호 (숫자 12~64자)"} size={"m"} onChange={onChangeInputs("password")} required
pattern={passwordPattern} title={"숫자 12자~64자"} onInvalid={onInvalid('사용할 수 없는 비밀번호입니다.')} onInput={onInput}/>
<Input01 type={"password"} placeholder={"비밀번호 확인 (숫자 12~64자)"} size={"m"} onChange={onChangeInputs("passwordCheck")} required
pattern={passwordPattern} title={"숫자 12자~64자"} onInvalid={onInvalid('사용할 수 없는 비밀번호입니다.')} onInput={onInput} />
<Button01 type={"submit"} text={"회원가입"} size={"m"} onClick={onClickSignUp}/>
</form>
</div>
어제 pattern, required 속성 찾아놓고 엄청 기뻐했는데 이게 react-hook-form 내용 안에 포함된 내용이었다 ㅋㅋㅋㅋㅋ
저번에 써놓고 그게 뭔지도 모르고 썼던거지...
그래서 오늘은 저 지저분한 코드를 고치고 훅으로 더 간결하고 편하게 바꿀 것이다.
연결하는 중에 React.forewardRef() 에러가 떴다.
공통 컴포넌트에 props를 해주니 해결!
yup과 watch, 이메일 정규식 유효성검사(이메일은 가입버튼이 아니라 메일 발송버튼으로 검증해야했다), setValue의 고통을 겪으며 완성..
<div className="signUp">
<form className="signUp-wrapper" onSubmit={handleSubmit(onClickSignUp)}>
<Logo height="55" role="img"/>
<div className="signUp__auth">
<Input01 type={"text"} placeholder={"이메일"} size={"s"} register={register("email")} disabled={watch("disabled")}/>
<Button01 type={"button"} text={"인증메일 발송"} size={"m"} onClick={onClickEmail} />
</div>
<div className="signUp__auth">
<Input01 type={"number"} placeholder={"인증번호"} size={"s"} register={register("authNum")}/>
<Button01 type={"button"} text={"인증번호 확인"} size={"m"} onClick={onClickAuth} />
</div>
<Input01 type={"text"} placeholder={"닉네임 (한글,영문,숫자 포함 2~8자)"} size={"m"} register={register("nickname")} />
<Error>{errors.nickname?.message}</Error>
<Input01 type={"password"} placeholder={"비밀번호 (숫자 12~64자)"} size={"m"} register={register("password")}/>
<Error>{errors.password?.message}</Error>
<Input01 type={"password"} placeholder={"비밀번호 확인 (숫자 12~64자)"} size={"m"} register={register("passwordCheck")} />
<Error>{errors.passwordCheck?.message}</Error>
<Button01 type={"submit"} text={"회원가입"} size={"m"}/>
</form>
</div>
);
};
어차피 버튼을 눌러서 값을 검증하는 방식이니 계속 값의 변화를 감지하는 watch보다는 입력되어있는 값을 불러오는 getValues를 사용하는게 맞을 것 같아서 처음에 watch를 썼다가 getValues로 수정했다.
하지만 인증번호 확인 성공 시 이메일 칸을 disabled로 만들어주기 위해 이메일 input창은 watch를 사용했다.
form 안의 input의 검증은 submit버튼을 눌러야 동작하기 때문에 disabled의 값을 동적으로 변경하려면 watch를 사용해야한다.
페이지 이동할때마다 로그인 검증을 해야하는데, 리액트로는 페이지 이동 시 렌더링이 안된다.
=> useEffect를 사용해서 로그인 상태값이 변경되면 렌더링하게 하면 되지 않을까?
=> 상태값을 어떻게 검증을 할 것인가?
파일 이름을 변경하고 commit 하면 반영이 되지 않는다.
이때 쓰는 명령어가 또 있구나
git mv [이전 파일명] [변경할 파일명]
해당 파일이 있는 디렉토리까지 들어가서 할 것!
오류가 나면 대소문자 설정을 변경하거나 -f 속성을 추가해 강제로 변경하면 된다.
참고 사이트
No routes matched location "/login" react router dom v6
[React] React-router 'Outlet' 사용하여 레이아웃 구성하기
[React] react-hook-form과 React.forwardRef() 에러
React hook form의 watch를 이용해서 입력 여부 확인하기
yup - npm
Git 파일명 대소문자 변경