React Router의 v6 업데이트가 힘들다고 합니다.
49024 단어 ReactTypeScriptReact Routertech
20초 개요
사용 중인 OSS를 업데이트하는 동안 React Router v5에서 v6 업데이트까지는 다소 힘들었습니다.
참고 자료
수정점 잡기
<Switch>
의 경로 분기는 <Routes>
입니다.<Route>
의 기본값은 완전히 일치하기 때문에exact가 필요하지 않습니다.<Switch>
내의 <Route>
순서에 주의할 필요가 없습니다./a
에서 지정한 경우 /a/b
와 같은 경로가 먼저 일치하지 않습니다.<Route>
의 매개 변수가 바뀌었습니다. element
에서 이동할 구성 요소를 지정했습니다.<Redirect>
가 <Navigate>
로 바뀌었다.useHistory
가 useNavigate
로 바뀌었다.<Redirect>
와 마찬가지로 기본적으로push를 나타낸다.useRouteMatch
가 useMatch
로 바뀌었다.무슨 곤란한 일이 있습니까?
후방 교환 없이 파괴적인 업데이트가 진행되었다.
상기 수정점에 대해서는 기계적으로 교체하면 되지만 참을 수 없는 점을 기계적으로 수정해 설명한다.
주의
딱한 곳
Routes의 직선 하단 구성 요소는 Route만 허용
v5 설치
지금까지 로그인 상황에 따라 로그인 화면으로 강제로 돌아가기 위해
<Route>
구성 요소 wrap<PrivateRoute>
을 제작했다.내용의 처리는 외부 부품과 자체 제작 갈고리를 이용하기 때문에 분위기만 전달하면 좋겠다고 생각합니다.
<Switch>
<Route path="/login">
<Login />
</Route>
<PrivateRoute path="/menu">
<Menu />
</PrivateRoute>
</Switch>
export const PrivateRoute: React.FC<RouteProps> = ({
children,
...props
}): JSX.Element => {
// 自作のuseLoginによるログイン処理の返却値を見て、ログイン状態を確認
// stateはグローバル状態としてユーザのログイン状態を管理
const { state } = useLogin();
// ログイン未済はログイン画面に遷移
return !state.authenticationStatus ? (
<Route {...props}>
<Login />
</Route>
) : (
// ログイン状態が問題無ければ画面遷移
<Route {...props}>
{children}
</Route>
);
};
v6에 대한 기계 수정
우선 기계적으로
<Switch>
를<Route>
으로, 변환 어셈블리도 element
지정으로 변경해 다음과 같은 오류가 발생했다.<Routes>
<Route path="/login" element={<Login />} />
<PrivateRoute path="/menu" element={<Menu />} />
</Routes>
router.tss:5 Uncaught Error: [PrivateRoute] is not a <Route> component. All component children of <Routes> must be a <Route> or <React.Fragment>
at invariant (router.tss:5:20)
at components.tsxx:291:5
at react.development.jss:1104:1
at react.development.jss:1067:1
at mapIntoArray (react.development.jss:964:1)
at mapIntoArray (react.development.jss:1004:1)
at mapChildren (react.development.jss:1066:1)
at Object.forEachChildren [as forEach] (react.development.jss:1103:1)
at createRoutesFromChildren (components.tsxx:275:3)
at Routes (components.tsxx:256:20)
v6의 공식 대응
마지막으로 다음과 같은 번잡한 문법이 되었다.
<Routes>
<Route path="/login" element={<Login />} />
<Route
path={screenLocations[MENU_FC]}
element={
<PrivateRoute path={screenLocations[MENU_FC]}>
<Menu />
</PrivateRoute>
}
/>
</Routes>
액세스 경로를 통해 Login 화면으로 리디렉션
v5 설치
지금까지 스위치의 어디도 일치하지 않는 상황에서 최종적으로
/login
Redirect를 진행했다.이 URL 자체도 /
가 아닌/login
이기 때문에 Redirect를 이용한다.<Switch>
<Route path="/login">
<Login />
</Route>
<Route path="/menu">
<Menu />
</Route>
<Redirect to="/login" />
</Switch>
v6에 대한 기계 수정
<Redirect>
는 <Navigate>
이기 때문에 다음과 같이 수정하면 이전 절과 같고<Routes>
의 부하<Route>
를 오류 출력으로 한다.(replace,push를 의식하지 못함)idnex.tsx
<Routes>
<Route path="/login">
<Login />
</Route>
<Route path="/menu">
<Menu />
</Route>
<Navigate to="/login" />
</Routes>
router.tss:5 Uncaught Error: [Navigate] is not a <Route> component. All component children of <Routes> must be a <Route> or <React.Fragment>
at invariant (router.tss:5:20)
at components.tsxx:291:5
at react.development.jss:1104:1
at react.development.jss:1067:1
at mapIntoArray (react.development.jss:964:1)
at mapIntoArray (react.development.jss:1004:1)
at mapChildren (react.development.jss:1066:1)
at Object.forEachChildren [as forEach] (react.development.jss:1103:1)
at createRoutesFromChildren (components.tsxx:275:3)
at Routes (components.tsxx:256:20)
v6의 공식 대응
마지막으로 우리는 다음과 같은 문법을 채택했다.
idnex.tsx
<Routes>
<Route path="/login" element={<Login />} />
<Route path="/menu" element={<Menu />} />
<Route
path="/"
element={<Navigate to={screenLocations[LOGIN_FC]} />}
/>
</Routes>
Routes 중첩 시 하위 Route를 와일드카드로 등록해야 함
v5 설치
<Switch>
<Route path="/login" exact>
<Login />
</Route>
<Route path="/menu">
<Menu />
</Route>
<Route path="/user">
<Users />
</Route>
</Switch>
<Switch>
<Route path="/user" exact>
<UserList />
</Route>
<Route path="/user/details">
<User />
</Route>
</Switch>
v6에 대한 기계 수정
<Routes>
<Route path="/login" element={<Login />} />
<Route path="/menu" element={<Menu />} />
<Route path="/user" element={<User />} />>
</Routes>
<Routes>
<Route path="/" elements={<UserList />} />
<Route path="/details" elements={<User />} />
</Routes>
VM1618 react_devtools_backend.js:3973 You rendered descendant <Routes> (or called `useRoutes()`) at "/workflow" (under <Route path="/user">) but the parent route path has no trailing "*". This means if you navigate deeper, the parent won't match anymore and therefore the child routes will never render.
Please change the parent <Route path="/user"> to <Route path="/user/*">.
v6는 하위 경로를 렌더링할 때 경로의 다음 경로를 와일드카드를 통해 허가해야 한다.이는 스위치가 더 이상 애매하지 않고 exact가 폐지된 것과 관련이 있어 정확한 루트를 진행하는 일환이라고 할 수 있다.
v6의 공식 대응
<Routes>
<Route path="/login" element={<Login />} />
<Route path="/menu" element={<Menu />} />
<Route path="/user/*" element={<User />} />>
</Routes>
<Switch>
<Route path="/" elements={<UserList />} />
<Route path="/details" elements={<User />} />
</Switch>
외국 편
업데이트에 따라 팩스를 진행하는 과정에서 수정이 발생했습니다. v6와는 상관없지만 조금 헷갈립니다.
현재 경로의 획득 방법을useRouteMatch에서useLocation으로 변경하면 "/" 가 사라집니다
원래useLocation에서 pathname을 얻었어야 했는데, 아래의 현재 경로를 얻었습니다.
const match = useRouteMatch();
return <Redirect to={`${match.path}details`} />;
useRouteMatch가useMatch가 된 일도 있다. 현재의 경로를 얻는 목적은 useLocation이나useHistory를 사용하는 것을 다시 변경했다.이때, location.pathname의 끝에
/
가 없기 때문에 다음과 같이 수정되었습니다.const location = useLocation();
return <Navigate to={`${location.pathname}/details`} />
※ v5에서는 useHistory에서 History까지.location.pathname처럼 현재 경로를 얻었습니다.useLoocation과 달리 useLoocation은 렌더링할 때 정음형이고 useHistory할 때 정음형이다.사용 장소를 명확히 구분해야 하는 경우는 드물지만, useHistory가 useNavigate로 바뀌었기 때문에 실제 useLocation에서 현재의 경로를 얻을 수 밖에 없다.끝맺다
왜 이렇게 파괴적인 업데이트가 있었을까? 스태프의 블로그에 언급됐다.
새 라우터가 발행되는 가장 큰 이유는 리액트 연계의 등장이다.
클래스에 React 구성 요소를 설치하지 말고 React와 연결된 함수 구성 요소를 이용하여 구성 요소의 흐름을 만듭니다.
리액트18에서도 화제
<React.Suspense>
와 React.lazy()
의 친화력을 다뤘고샘플 코드도 제공했다.또 v5와의 후방 교환도 개발 중이다.
Reference
이 문제에 관하여(React Router의 v6 업데이트가 힘들다고 합니다.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/khale/articles/react-router-update-v6텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)