React Router: v5에서 업데이트
45888 단어 react
데모 앱은 here 입니다.
스위치 -> 경로
Switch 대신 Routes를 사용하고 v6에서는 정확한 키워드가 필요하지 않습니다. 또한 element는 Route 페이지 내부에 컴포넌트를 할당하는 새로운 속성입니다.
v5
<Switch>
<Route path="/" exact>
<LaunchPage />
</Route>
<Layout>
<Switch>
<Route path="/search-book">
<Home />
</Route>
<Route path="/my-books">
<MyBooks />
</Route>
</Switch>
</Layout>
</Switch>
v6
사소한 발견은 라우트 내부에 레이아웃 구성 요소를 넣는 것이 불가능하다는 것입니다. 따라서 Layout에서 각 페이지 구성 요소를 각각 래핑해야 합니다. 또한 라우터가 경로에 하나 이상의 하위 경로가 있음을 알리려면 "*"가 중요합니다.
<Routes>
<Route path="/" element={<LaunchPage />} />
<Route path="search-book/" element={<Layout><Home /></Layout>} />
<Route path="my-books" element={<Layout><MyBooks /></Layout>}/></Routes>
**리팩토링
Routes에서 반복되는 패턴을 피하기 위해 WithLayout 구성 요소와 래핑된 페이지 구성 요소를 추가했습니다.
레이아웃 포함
import Layout from "../Layout/Layout.jsx";
function WithLayout(Child) {
return function WithLayout(props) {
return (
<Layout>
<Child {...props} />
</Layout>
);
};
}
export default WithLayout;
집
import SearchBooks from "../components/SearchBooks";
import WithLayout from "../hoc/WithLayout";
const Home = () => {
return <SearchBooks />;
};
export default **WithLayout(Home)**;
내 책들
import { Fragment, useContext } from "react";
import MyBookItem from "../components/MyBookItem";
import SortMyBooks from "../components/SortMyBooks";
import MyBooksContext from "../store/my-books-context";
import classes from "./MyBooks.module.css";
import WithLayout from "../hoc/WithLayout";
// functions
const MyBooks = () => {
// functions
return (
<Fragment>
<SortMyBooks
onTitle={sortByTitleHandler}
onDate={sortByDateHandler}
onRating={sortByRatingHandler}
onDefault={defaultHandler}
/>
<div className={classes.box}>
{myBooksCtx.myBooks.length !== 0 && content}
{myBooksCtx.myBooks.length === 0 && (
<p>No books here yet. Let's add your book!</p>
)}
</div>
</Fragment>
);
};
export default **WithLayout(MyBooks)**;
찾을 수 없음
import React from "react";
import { Link } from "react-router-dom";
import classes from "./NotFound.module.css";
import WithLayout from "../hoc/WithLayout";
function NotFound() {
return (
<div className={classes["not-found"]}>
<h1>404</h1>
<h2>Page Not Found </h2>
<p>
Back to <Link to="/search-book">Home</Link>
</p>
</div>
);
}
export default WithLayout(NotFound);
앱
import React, { Fragment, Suspense } from "react";
import { Route, Routes } from "react-router-dom";
import LaunchPage from "./pages/LaunchPage";
import Home from "./pages/Home";
import LoadingSpinner from "./UI/LoadingSpinner";
import NotFound from "./pages/NotFound";
const MyBooks = React.lazy(() => import("./pages/MyBooks"));
function App() {
return (
<Fragment>
<Suspense
fallback={
<div className="centered">
<LoadingSpinner />
</div>
}
>
<Routes>
<Route path="/" element={<LaunchPage />} />
<Route path="search-book/*" element={<Home />} />
<Route path="my-books" element={<MyBooks />} />
<Route path="*" element={<NotFound />} />
</Routes>
</Suspense>
</Fragment>
);
}
export default App;
전체 경로 -> 상대 경로
하위 경로를 추가할 때 상대 경로를 사용하는 반면 v5에서는 전체 경로를 사용해야 했습니다.
v5
<Route path={match.url} exact>
//*elements*
</Route>
<Route path={`${match.url}/add-my-books`}>
<AddMyBooks />
</Route>
v6
<Routes>
<Route path="" element={
<BookDetailComponent path={location.pathname} />
}/>
<Route path="add-my-books" element={<AddMyBooks />} />
</Routes>
useRouteMatch -> useLocation
공식 문서에 따르면 useMatch는 useRouteMatch의 대안입니다. 그러나 useRouteMatch를 사용하는 방식에 따라 useLocation이 대안이 될 수 있습니다. 필자의 경우 이전 경로를 알기 위해 useRouteMatch를 사용했는데 useLocation이 대체 솔루션이 된 경우입니다.
v5
const BookItem = (props) => {
const itemCtx = useContext(ItemContext);
const match = useRouteMatch();
const updateItemHandler = () => {
itemCtx.updateItem(props.item);
};
return (
<Fragment>
<Link
className={classes.box}
to={`${match.path}/${props.item.id}`}
onClick={updateItemHandler}
>
<img
className={classes.image}
src={props.item.image ? props.item.image : noImage}
alt={props.item.title}
></img>
</Link>
</Fragment>
);
};
v6
const BookItem = (props) => {
const itemCtx = useContext(ItemContext);
const location = useLocation();
const updateItemHandler = () => {
itemCtx.updateItem(props.item);
};
return (
<Fragment>
<Link
className={classes.box}
to={`${location.pathname}/${props.item.id}`}
onClick={updateItemHandler}
>
<img
className={classes.image}
src={props.item.image ? props.item.image : noImage}
alt={props.item.title}
></img>
</Link>
</Fragment>
);
};
useHistory -> useNavigate
useHistory는 더 이상 사용할 수 없으며 이전 페이지에서 다른 페이지로 이동하려는 경우 대신 useNavigate를 사용하십시오.
v5
const history = useHistory();
const submitHandler = (event) => {
event.preventDefault();
const formattedDate = formatDate(inputDate);
const mybook = {
id: "" + inputDate.getTime() + itemCtx.item.id,
date: formattedDate,
rating,
title: itemCtx.item.title,
authors: itemCtx.item.authors,
image: itemCtx.item.image,
comment,
};
myBooksCtx.updateMyBooks(mybook);
history.replace("/my-books");
};
v6
교체할 때 지정할 개체를 넣습니다.
const navigate = useNavigate();
const submitHandler = (event) => {
event.preventDefault();
const formattedDate = formatDate(inputDate);
const mybook = {
id: "" + inputDate.getTime() + itemCtx.item.id,
date: formattedDate,
rating,
title: itemCtx.item.title,
authors: itemCtx.item.authors,
image: itemCtx.item.image,
comment,
};
myBooksCtx.updateMyBooks(mybook);
navigate("/my-books", { replace: true });
};
활성 클래스 이름 -> isActive
activeClassName이 삭제되었고 대신 isActive를 사용하여 특정 탐색이 활성화되었는지 여부를 인식해야 합니다.
v5
const MainNavigation = () => {
return (
<header className={classes.header}>
<div className={classes.logo}>Your Library</div>
<nav className={classes.nav}>
<ul>
<li>
<NavLink to="/search-book" exact activeClassName={classes.active}>
Home
</NavLink>
</li>
<li>
<NavLink to="/my-books" activeClassName={classes.active}>
My Books
</NavLink>
</li>
<li>
<NavLink to="/" exact activeClassName={classes.active}>
Logout
</NavLink>
</li>
</ul>
</nav>
</header>
);
}
v6
const MainNavigation = () => {
return (
<header className={classes.header}>
<div className={classes.logo}>Your Library</div>
<nav className={classes.nav}>
<ul>
<li>
<NavLink
to="/search-book"
className={({ isActive }) => (isActive ? classes.active : null)}
>
Home
</NavLink>
</li>
<li>
<NavLink
to="/my-books"
className={({ isActive }) => (isActive ? classes.active : null)}
>
My Books
</NavLink>
</li>
<li>
<NavLink
to="/"
className={({ isActive }) => (isActive ? classes.active : null)}
>
Logout
</NavLink>
</li>
</ul>
</nav>
</header>
);
};
리디렉션 -> 탐색
Redirect를 사용하지는 않았지만, Redirect의 삭제는 v5에서 또 다른 큰 변화라고 생각합니다. 대체 구성 요소는 탐색이지만 속성이 약간 변경되었습니다. 리디렉션에서는 교체가 기본값이었고 필요한 경우 푸시를 사용했습니다. 반면에 탐색에서는 푸시가 기본값이며 바꾸기를 사용해야 합니다.
v5
<Redirect to="contactme" />
<Redirect to="home" push />
v6
<Navigate to="contactme" replace />
<Navigate to="home" />
the official document 에서 더 자세한 정보를 찾을 수 있습니다.
이 업데이트에 대한 나의 인상은 v6에서 중첩 경로를 처리하기가 더 쉬워진다는 것입니다. 또한 요소를 사용하기 때문에 페이지 구성 요소와 기타 구성 요소를 분리하는 것이 더 중요해집니다. 그러나 activeClassName을 삭제하는 것은 나에게 약간 불편합니다.
읽어 주셔서 감사합니다 :)
원문은 here
Reference
이 문제에 관하여(React Router: v5에서 업데이트), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/lada496/react-router-updating-from-v5-kjj텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)