Tìm kiếm trang web

reactjs - react-router chuyển hướng không thay đổi URL trong Switch


Tôi đang sử dụng react-router để thiết lập ứng dụng của mình, và cố gắng sử dụng <Redirect/> để thiết lập router cho xác thực.

Thành phần Route có hai thành phần khác nhau, một là private Route, cái còn lại là public route.

Kết quả mong đợi: khi auth là false, trang nên quay trở lại một trang công khai, tôi đã thiết lập <Redirect to={"/public"} /> cho đến nay có vẻ route hoạt động bình thường, nhưng redirect không hoạt động đúng. Mọi ý tưởng đều được hoan nghênh! Cảm ơn!!

PrivateRoute
interface PrivateRouteProps {
  isLogin: boolean;
  privateRoutes: RouteItem[];
}

const PrivateRoute: React.FunctionComponent<PrivateRouteProps> = (
  props: PrivateRouteProps
) => {
  return (
    <>
      {props.isLogin ? (
        props.privateRoutes.map(item => {
          return <Route key={item.path} {...item} />;
        })
      ) : (
        <Redirect to={PUBLIC.path} />
      )}
    </>
  );
};
PublicRoute
interface PublicProps {
  publicRoutes: RouteItem[];
}

const PublicRoute: React.FC<PublicProps> = (props: PublicProps) => {
  return (
    <>
      {props.publicRoutes.map(route => (
        <Route key={route.path} {...route} />
      ))}
    </>
  );
};
Route
<BrowserRouter>
      <Switch>
        <PublicRoute publicRoutes={publicRoutes} />
        <PrivateRoute privateRoutes={privateRoutes} isLogin={login} />
      </Switch>
    </BrowserRouter>

CẬP NHẬT Như câu trả lời được chấp nhận đã đề cập, tất cả đều liên quan đến cách <Switch/> hoạt động với Fragment, vì vậy tôi đã chỉnh sửa các tuyến đường của mình như sau, nó hoạt động rất tốt. Chỉ cập nhật để ai đó có thể có câu hỏi tương tự.

<BrowserRouter>

            <Switch>
                {publicRoutes.map(item => {
                    return <Route key={item.path} {...item}/>
                })}
                {privateRoutes.map(item => {
                    return <PrivateRoute key={item.path}
                                         exact={item.exact}
                                         component={item.component}
                                         path={item.path}
                                         redirectPath={SIGN_IN.path}
                    />

      })}
            </Switch>
        </BrowserRouter>

Câu trả lời #1

Tôi đã xem qua mã của bạn và vấn đề tóm gọn lại ở một điều. Cách mà component <Switch> hoạt động với fragment <></>. Nó chỉ tìm kiếm React Fragment đầu tiên vì họ không muốn duyệt qua một cây:

https://github.com/ReactTraining/react-router/issues/5785

Để giải quyết vấn đề đó, bạn cần hoặc loại bỏ React.Fragment bên trong các thành phần của bạn. Vì vậy, ứng dụng của bạn sẽ trông như sau:

<Switch> 
    <Route ...>
    <Route ...>
    <Route ...>
</Switch>

và KHÔNG (nhân tiện, đó là cách nó đang như bây giờ)

      <Switch> 
    //it will only sees the first one //if you switch orders - Private with Public
    // Private will work but not Public anymore :(
        <React.Fragment>
            <Route ...>
            <Route ...>
        </React.Fragment>
        <React.Fragment>
            <Route ...>
        </React.Fragment>
     </Switch>

Một giải pháp khác (đó là những gì tôi đã làm vì tôi không thành thạo TypeScript đủ để thay đổi kiểu và giá trị trả về) là thêm một wrapper trong ứng dụng switch của bạn và xử lý giá trị trả về của các Routes riêng tư bằng cách sử dụng phương thức render bên trong <Route> như được minh họa dưới đây:

  //index.tsx
        <Switch>
            <>
            <PublicRoute publicRoutes={publicRoutes}/>
            <PrivateRoute privateRoutes={privateRoutes} isLogin={login}/>
            </>
        </Switch>

Điều đó dẫn đến một lỗi khác của việc re-render vòng lặp vô hạn (một lần nữa react-router có khả năng gặp rắc rối với các tuyến đường lồng nhau) và để giải quyết điều đó, bạn sẽ thực hiện những điều sau với component PrivateRoutes của bạn:

  //PrivateRoute.tsx
return (
    <>
        {props.privateRoutes.map(item =>
            <Route key={item.path} exact path={item.path} render={() => (
                !props.isLogin
                    ? (
                    <Redirect to={PUBLIC.path}/>
                ):
                    //HOC transforming function Component into Component
                    // @ts-ignore (you can deal here better than me hehehe)
                    ((PrivateComponent)=><PrivateComponent/>)(item.component)
            )}/>)}
    </>
);

Tóm tắt: Bạn đang thêm độ phức tạp lồng nhau bằng cách thêm <></> (dịch ra là React.Fragment) vào trong cấu trúc của bạn. Nếu bạn loại bỏ chúng hoặc làm theo mã ở trên, bạn sẽ ổn thôi

Hy vọng tôi đã giúp được bạn. Chúc may mắn! :)

Bài viết liên quan