숙제를 몇 번이고 봤지만 무슨말인지 잘 이해가 되지 않았다...
난 대체 어느 수준인지에 대해 약간 자괴감을 느꼈다.
결국 다른 분꺼 숙제의 흐름을 따라가면서 떠듬떠듬 해보기로 했다.
일단 뭔가를 띄워냈다는 것에 . . . ㅎㅎ
일단 이건 app.jsx에서 만든 AppRouters를 불러왔을 때의 모습
"/"로 해도 "/about"이 되고 컴포넌트 두 개가 모두 동시에 뜬다.
여기서부턴 혼자 좀 생각을 해보자...
import AboutPage from "../pages/About";
import MainPage from "../pages/Main";
import Route from "./Route";
import Router from "./Router";
export default function AppRouters() {
return (
<Router>
<Route path="/" component={<MainPage />} />
<Route path="/about" component={<AboutPage />} />
</Router>
);
}
AppRouter 구조는 이렇게 생겼다.
path랑 component를 받는 Route는,
import { useEffect } from "react";
export default function Route({ path, component, state }) {
useEffect(() => {
window.history.pushState(state, "", path);
}, [path]);
return component;
}
path가 바뀌면 pushState하고 받은 component를 뱉는다.
pushState에 대해서
import { useEffect } from "react";
export default function Route({ path, component, state }) {
useEffect(() => {
window.history.pushState(state, "", path);
}, [path]);
return path === window.location.pathname ? component : "";
}
그래서 윈도우 주소랑 path가 같을 때만 그 컴포넌트를 뱉는 식으로 바꿨다.
about에선 about만 잘 뜨는데, "/"를 입력했을 땐 주소가 about이 되고 Main이 뜬다.
왜 자꾸 주소가 "/about"이 되는거지?
path와 window.location.pathname을 찍어보았다.
...??? 침착. path가 들어오면, pushState로 window.location.pathname와 path가 같아진다!
그러면 같아졌으니까 해당 컴포넌트를 뱉는다! 메인 컴포넌트,,!!!
근데 이거 이후에 "/about"으로 바뀌고 pathname도 바뀌었는데 또 번갈아바뀌고ㅋ(?????????)
계속 main을 보여주는 것도 이해가 안된다.
- 일단 주소가 계속 바뀌는 이유는 쉬웠다... 함수는 위에서 아래로 읽는다~~~~
AppRouter 또한 path="/"로 전달하고, 그 후에 "/about"으로 무조건 순서대로 두 개를 전달한다. 왜냐면 그렇게 쓰여있으니까...그치!...
- 그럼 무조건 about주소에 about 페이지만 보여야하는 거 아닌가? 왜 메인이 나오지?
path 랑 pathname이 같은 메인을 뱉는다. 그리고 같지 않으면 ""을 리턴하게 해놨으니 about 담당하는 애는 아무것도 보여주지 않는다! 근데 useEffect에 path가 변경됐으니 pushState를 한다. 이건 리렌더링을 하지 않기 때문에 보이던 메인이 그대로 계속 보이는 것이다!!!!!!!!!!!~~ (추측)
- 일단 path가 변경되면 리렌더링을 일으켜야 한다. 그러나 새로고침은 안된다(ㅋ)... 그것이 SPA니까...
리렌더링을 일으킬 수 있는 가장 쉬운 방법은?! state가 아닐까...?
import { useState } from "react";
import { useEffect } from "react";
export default function Route({ path, component, state }) {
const [pathState, setPath] = useState(path);
useEffect(() => {
setPath(path);
window.history.pushState(state, "", pathState);
}, [pathState]);
return path === window.location.pathname ? component : "";
}
응 안됨
그리고 너무 웃긴 방법이긴 하다...
누가보는건 아니지만 황급히 코드를 지웠다...
export default function AppRouters() {
const { pathname } = location;
return (
<Router>
{pathname === "/" && <Route path="/" component={<MainPage />} />}
{pathname === "/about" && (
<Route path="/about" component={<AboutPage />} />
)}
</Router>
);
}
조건에 따라 보이게 해줬는데 왜케 이게 아닌 것 같을까?
아무튼, 주소에 따라 다른 게 나오는 것은 된다!
다시 블로그 보고 useRouter를 쓰는 방향으로 고쳐보았다,,~
그러나 About 버튼을 눌렀을 때 pathname만 변경되고, 뱉는 컴포넌트는 바뀌지 않는다.
import { useEffect } from "react";
import { useRouter } from "../common/hooks/useRouter";
export default function Route({ path, component, state }) {
const { push } = useRouter();
useEffect(() => {
push(path);
}, [window.location.pathname]);
return path === window.location.pathname ? component : "";
}
이렇게 바꿔도 안돼! 라고 쓰려고 했는데 당연하다. 새로운 push가 필요한 게 아니라, return 하는 컴포넌트가 바뀌어야 하는거니까, ,,
import { useState } from "react";
import { useEffect } from "react";
export default function Route({ path, component, state }) {
const [pathState, setPathState] = useState(path);
useEffect(() => {
setPathState(path);
}, [window.location.pathname]);
return pathState === window.location.pathname ? component : "";
}
부끄럽지만 아까 같은 state를 다시 써봤는데 안된다ㅎㅎ~~~ 왜...? 아예 useEffect 안으로 들어오질 않는다.
버튼을 눌러도 window.location.pathname은 변하지 않는다.
window.history.pushState는 pathname을 변하게 하지 않는거야? 그건 아닌 것 같은데
내 눈에 보이는 이 주소가 pathname아닌가?? 대혼돈
맞는데 리렌더링이 안돼서 그런거였다.
import { useEffect } from "react";
import { useRecoilState } from "recoil";
import { pathState } from "../common/library/state";
import AboutPage from "../pages/About";
import MainPage from "../pages/Main";
import Route from "./Route";
import Router from "./Router";
export default function AppRouters() {
const { pathname } = location;
const [pathnameState, _] = useRecoilState(pathState);
useEffect(() => {
if ((pathname === pathState) === "/") {
console.log("메인이어야합니다.");
} else if ((pathname === pathState) === "/about") {
console.log("about이어야합니다.");
}
}, [pathnameState]);
return (
<Router>
{pathname === "/" && <Route path="/" component={<MainPage />} />}
{pathname === "/about" && (
<Route path="/about" component={<AboutPage />} />
)}
</Router>
);
}
결국 난 recoil과 이상한 console.log(의미없음)을 추가했다.
recoil은 리렌더링을 위해서... 넣어보았다... 그리고 관리가 더 편하지 않을까 싶기도 하고...
import { useRecoilState } from "recoil";
import { pathState } from "../library/state";
export const useRouter = () => {
const [_, setPathState] = useRecoilState(pathState);
function push(path) {
setPathState(path);
return window.history.pushState(null, "", path);
}
return { push };
};
다소 이상한 useRouter도 만들었다~^^ 아냐 괜찮은 걸 수도 있어
뒤로가기도 안되고 앞으로 가기도 안된다..
시간은 엄청 오래걸렸는데 전부 해내진 못했다.
그래도 버튼으로 왔다갔다는 할 수 있다!
보고라도 해보긴 잘한 것 같다.
참고 블로그
React와 History API 사용하여 SPA Router 기능 만들어보기
개발하면서 겪은 것을 이야기로 풀어보는 블로그
movie42.github.io
감사합니다.
'프론트엔드✏️ > 개인공부' 카테고리의 다른 글
[css] 가상 요소, hover transition, 그라디언트 transition 주기 (0) | 2022.10.13 |
---|---|
[styled-component] 마우스 hover effect (0) | 2022.10.12 |
[Next.js] Next.js 설치 (1) | 2022.10.07 |
[react] Modal 스크롤 막기 (0) | 2022.10.05 |
[css] 자릿수 계산하기,,, 고정되지 않은 width값 transition 주는 방법 알고 싶다. (0) | 2022.09.27 |