이번 프로젝트에선 라우트를 v6를 사용하면서 기록을 하기 위해 남긴다.
v6에서는 BrowserRouter를 사용하지 않고 createBrowserRouter를 사용한다.
createBrowserRouter를 사용하면서 javaScript Objcet로 사용할수 있다.
const router = createBrowserRouter([
{
path: "/",
element: <App />,
},
]);
여기서 더이상 이제 index.tsx에서는 App을 렌더링 할필요가 없어진다.
<React.StrictMode>
<RouterProvider router={router} />
//없어짐 <App />
</React.StrictMode>
const router = createBrowserRouter([
{
path: "/",
element: <App />,
children: [
{
path: "screen",
element: <Screen />,
},
],
},
]);
여기서 이제 거의 다된거 같지만 실제로 /Screen 으로 이동하게 되면 브라우저는 아무런 반응 해주지 않는다
App의 자식을 render하길 원한다고 직접 전달해줘야한다.
이유는 아직 "/" 안에 있고 그안에 Screen을 포함하고 있기 때문이다.
function App() {
return (
<div>
<Outlet />
</div>
);
}
Outlet이라는 컴포넌트를 통해 유저가 Screen페이지로 가면 reactRouter가 App를 보고 Outlet을 Screen으로 대체해달라! 요구 하면되는거다.
reactRouterV6의 장점으로는 에러를 컨트롤할수 있다는 점인데 매우 간단하고 직관적이다.
const router = createBrowserRouter([
{
path: "/",
element: <App />,
children: [
{
path: "screen",
element: <Screen />,
},
],
errorElement: <NotFound />,
},
]);
const router = createBrowserRouter([
{
path: "/",
element: <App />,
children: [
{
path: "screen",
element: <Screen />,
errorElement: <ErrorComponent />,
},
],
errorElement: <NotFound />,
},
]);
errorElement를 사용하지 않으면 사용하는 앱이 죽어버리기 때문에 사용하는걸 권장한다.
useNavigate는 유저를 이동시키거나 유저가 이동하고 싶은 곳으로 갈수있게 도와준다.
<header>
<ul>
<li>
<Link to={"/"}>Home</Link>
</li>
<li>
<Link to={"/screen"}>screen</Link>
</li>
</ul>
</header>
useNavigate 사용
const navigate = useNavaigate();
const onScreenClick = () => {
navigate("/screen")
}
return(
<header>
<ul>
<li>
<Link to={"/"}>Home</Link>
</li>
<li>
<button onClick={onScreenClick}>screen</button>
</li>
</ul>
</header>
)
useParam
const users =[
{
id:1,
name:"a"
},
{
id:2,
name:"b"
}
]
user의 가상의 데이터가 있다고 가장하고 이유저의 대해 상세정보를 보고 싶거나 상세정보를 보기위한 component를 보고싶다면 useParam을 사용한다.
return (
<div>
<h1>Users</h1>
<ul>
{users.map((el) => (
<li key={el.id}>
<Link to={`/users/${el.id}`}>{el.name}</Link>
</li>
))}
</ul>
</div>
);
실제로 URL의 parameter로 유저를 보낼수 있다. 실제로 이동하면 NotFound컴포넌트가 보여지면서 페이지는 원하는 곳으로 갈수 없다.
router 컴포넌트에 users/라는 페이지에서 내가 선택한 유저의 상세정보를 볼수있게 작성해야한다. URL이 parameter를 가졌으니 알려준다고 보면된다.
router = createBrowserRouter([
{
path: "/",
element: <App />,
children: [
{
path: "about",
element: <Screen />,
errorElement: <ErrorComponent />,
},
//추가된부분
{
path: "users/:userId",
element: <User />,
},
],
errorElement: <NotFound />,
},
]);
여기까지 3가지에 매칭되는데 "/" 매칭되니까 App를 rander되고
Outlet을 rander할테고 그다음 users를 찾게 되고 userId가 있다는걸 알게되 그러면 여기서userId가 뭔지 알려주면 끝이다.
const {userId} = useParams();
return <h1>User {userId}의 이름은 {users[Number(userId)-1].name}
</h1>
useParams에는 원하는걸 넣어주면되는데 현재 지금 내가 필요한건 userId가 필요하다.
만약 users만 있는 페이지를 보여주고싶다면??
router = createBrowserRouter([
{
path: "/",
element: <App />,
children: [
{
path: "about",
element: <Screen />,
errorElement: <ErrorComponent />,
},
{
path: "users",
element:<UserHome/>,
children :[{
path:"userId",
element:<User/>
}]
},
],
errorElement: <NotFound />,
},
]);
위코드로 하면 페이지를 찾을수 없다고 나오는데.. 이유를 모르겠따..
이동하는 div 태그에도 파라미터값을 받아서 링크로 이동할수 있게끔 했는데.. 왜 안될까..
결국엔 자식으로 두지 않았다..
후..이유를 찾지 못했는데 공식문서를 좀 다시 들여다봐야겠다..
router = createBrowserRouter([
{
path: "/",
element: <App />,
children: [
{
path: "about",
element: <Screen />,
errorElement: <ErrorComponent />,
},
{
path: "users",
element:<UserHome/>,
errorElement: <ErrorComponent/>
},
{
path: "user/:userId",
element:<UserHome/>,
errorElement: <ErrorComponent/>
},
],
errorElement: <NotFound />,
},
]);
마지막으로 정말 신박한 기능!! 페이지로 넘어갈떄 이떄 props나 import를 통해서 자식이게 데이터를 전달했는데 새로 업데이트된 라우터에서는 RouterContext로 자식에게 데이터를 전달할수 있다.
<div>
<h1>
{userId}의 이름은 {users[Number(userId) - 1].name}
</h1>
<Link to="follower">Follower</Link>
<Outlet context={{ name: "chan" }} />
</div>
자식컴포넌트에서 데이터를 받아주기만 하면된다.
export default function Follower() {
const ctx = useOutletContext();
return <div>Follower</div>;
}