0
0
Lập trình
Admin Team
Admin Teamtechmely

TanStack Router: Quay lại trang trước sau khi Đăng Nhập

Đăng vào 7 tháng trước

• 6 phút đọc

Giới thiệu

Chào mừng bạn trở lại với chuỗi bài viết về TanStack Router! Trong chương 10 này, chúng ta sẽ giải quyết một vấn đề người dùng thường gặp khi thực hiện quy trình xác thực. Khi bạn điều hướng đến một trang và được yêu cầu đăng nhập, sau đó bạn lại bị chuyển hướng đến trang chủ, và mọi dữ liệu hoặc bộ lọc bạn đã thiết lập đều biến mất. Bài viết này sẽ hướng dẫn bạn hai cách để chuyển hướng người dùng trở lại trang mà họ đã ở trước khi đăng nhập, giữ nguyên các tham số truy vấn.

Vấn đề cần giải quyết

Khi bạn đăng nhập, bạn bị chuyển hướng về trang chính và mất đi các tham số trang mà bạn đã thiết lập trước đó.

Cách 1: Chuyển hướng rõ ràng qua tham số tìm kiếm

Đây là giải pháp đơn giản và đáng tin cậy. Chúng ta sẽ truyền tham số redirectTo đến mọi nơi mà người dùng có thể điều hướng đến trang đăng nhập. Sau đó, chúng ta sẽ sử dụng tham số này để quay lại trang sau khi đăng nhập thành công.

Ví dụ về thành phần Đăng Nhập

javascript Copy
export const SignInForm = ({ redirectTo = '/' }: { redirectTo?: string }) => {
  const navigate = useNavigate();

  const signIn = () => {
    // Logic đăng nhập của bạn tại đây

    navigate({ to: redirectTo });
  };

  return (
    <form onSubmit={signIn}>
      {/* trường nhập liệu */}
      <Button type="submit">Đăng Nhập</Button>
    </form>
  );
};

Tham số redirectTo được lấy từ đâu? Chúng ta sẽ thêm nó như một tham số tìm kiếm vào định tuyến đăng nhập.

Định tuyến đăng nhập

javascript Copy
import { createFileRoute } from '@tanstack/react-router';
import { SignInForm } from 'src/components/auth/sign-in-form';
import { Layout } from 'src/components/layout';
import { z } from 'zod';

export const Route = createFileRoute('/sign-in')({
  component: RouteComponent,
  validateSearch: z.object({
    redirectTo: z.string().optional().catch('/'),
  }),
  // ...
});

function RouteComponent() {
  const { redirectTo } = Route.useSearch();

  return (
    <Layout>
      {/* ... */}
      <SignInForm redirectTo={redirectTo} />
      {/* ... */}
    </Layout>
  );
}

Giải thích về validateSearch

validateSearch sử dụng Zod để phân tích các tham số tìm kiếm và trích xuất redirectTo, mặc định là / nếu không được cung cấp. Trong thành phần, chúng ta đọc nó bằng Route.useSearch() và truyền xuống SignInForm.

Nếu bạn muốn tìm hiểu thêm về cách xử lý các tham số tìm kiếm với TanStack Router, hãy tham khảo bài viết trước của tôi: Xử lý Tham số Truy vấn.

Bước tiếp theo

Đảm bảo rằng mọi liên kết đến trang đăng nhập đều bao gồm tham số redirectTo. Dưới đây là một ví dụ trong thành phần Header:

javascript Copy
import { useRouter } from '@tanstack/react-router';
import { ButtonLink } from '../button-link';

export const Header = () => {
  const router = useRouter();

  return (
    <header>
      {/* ... */}

      <ButtonLink to="/sign-in" search={{ redirectTo: router.state.location.href }}>
        Đăng Nhập
      </ButtonLink>
      {/* ... */}
    </header>
  );
};

Lưu ý

ButtonLink là một thành phần bọc có kiểu dáng xung quanh thành phần Link từ TanStack Router. Bạn có thể sử dụng Link trực tiếp nếu bạn muốn hoặc tìm hiểu cách tạo thành phần liên kết tùy chỉnh của riêng bạn qua video mà tôi đã làm về nó: Video về Link.

Với cách này, sau khi đăng nhập thành công, bạn sẽ trở lại trang gốc bao gồm tất cả các tham số tìm kiếm.

Nhược điểm của cách tiếp cận rõ ràng

Bạn phải nhớ thêm tham số redirectTo trong mọi liên kết đến trang đăng nhập. Đây không phải là vấn đề lớn, và bạn có thể gói nó trong một hàm trợ giúp hoặc hook tùy chỉnh như một tiện ích "đi đến đăng nhập", nhưng vẫn là thêm một việc cần làm.

Cách 2: Tự động ghi lại vị trí trước đó

Tôi cũng đã thử nghiệm với một hook nhỏ theo dõi vị trí trước đó mà không cần phải truyền bất kỳ tham số tìm kiếm nào đến trang đăng nhập. Tôi không hoàn toàn chắc chắn về tính ổn định và đáng tin cậy của nó, nhưng nó đã hoạt động tốt trong các thử nghiệm của tôi, vì vậy tôi nghĩ rằng nó đáng để chia sẻ:

javascript Copy
function usePreviousLocation() {
  const router = useRouter();
  const [previousLocation, setPreviousLocation] = useState<string>('/');
  useEffect(() => {
    return router.subscribe('onResolved', ({ fromLocation }) => {
      setPreviousLocation(fromLocation?.href ?? '/');
    });
  }, []);
  return previousLocation;
}

Cách sử dụng hook này

Hook này đăng ký sự kiện điều hướng của router và ghi lại vị trí "từ" sau mỗi lần điều hướng. Nó lưu trữ nó trong state để có thể sử dụng sau này.

Với cách này, bạn không cần phải lo lắng về việc truyền redirectTo trong mỗi lần điều hướng hoặc xử lý tham số tìm kiếm. Chỉ cần sử dụng hook này trong thành phần đăng nhập:

javascript Copy
export const SignInForm = () => {
  const navigate = useNavigate();
  const previousLocation = usePreviousLocation();

  const signIn = () => {
    // Logic đăng nhập của bạn tại đây

    navigate({ to: previousLocation });
  };

  return (
    <form onSubmit={signIn}>
      {/* trường nhập liệu */}
      <Button type="submit">Đăng Nhập</Button>
    </form>
  );
};

Kết hợp cả hai để có trải nghiệm người dùng tốt hơn

Hai cách tiếp cận này có thể hoạt động tốt cùng nhau. Bạn có thể ưu tiên redirectTo rõ ràng khi có, và quay lại vị trí đã ghi lại trước đó khi không có. Điều này bao gồm cả việc chuyển hướng có chủ đích và hành vi mặc định mà không cần thêm nỗ lực.

javascript Copy
export const SignInForm = ({ redirectTo }: { redirectTo?: string }) => {
  const navigate = useNavigate();
  const previousLocation = usePreviousLocation();

  const signIn = () => {
    // Logic đăng nhập của bạn tại đây

    navigate({ to: redirectTo ?? previousLocation });
  };

  return (
    <form onSubmit={signIn}>
      {/* trường nhập liệu */}
      <Button type="submit">Đăng Nhập</Button>
    </form>
  );
};

Lưu ý

  • Bài viết này tập trung vào TanStack Router, nhưng ý tưởng tương tự cũng áp dụng cho TanStack Start.
  • Nếu bạn đang sử dụng các định tuyến hoặc bảo vệ đã xác thực, bạn có thể thích bài viết liên quan này: Định tuyến và Bảo vệ đã xác thực.

Kết luận

Vậy là xong! Với cả hai phương pháp chuyển hướng rõ ràng hoặc ghi lại vị trí trước đó, bạn có thể tạo ra quy trình đăng nhập giúp người dùng quay lại đúng nơi họ đã rời đi, giữ nguyên các tham số truy vấn và ngữ cảnh của họ.

Nếu bạn có những ý tưởng khác hoặc cải tiến nào, hãy cho tôi biết trong phần bình luận.

Mã nguồn được lấy từ dự án ConfHub, bạn có thể tìm thấy nó ở đây: ConfHub GitHub.


Cảm ơn bạn đã đọc bài viết này, tôi hy vọng bạn thấy nó hữu ích!

Hãy kết nối với tôi nhiều hơn tại: Newsletter.

Bạn có thích nội dung của tôi không? Bạn có thể xem xét đăng ký kênh YouTube của tôi! Điều này có ý nghĩa rất lớn với tôi ❤️.

Bạn có thể tìm thấy kênh của tôi tại: DevLeonardo.

Hãy theo dõi tôi để nhận thông báo khi có bài viết mới nhé ;)

Theo dõi Leonardo Montini

Được trao tặng GitHub Star từ năm 2023 ⭐️ và Microsoft MVP từ năm 2024 🔷, tôi nói về Open Source, GitHub và Phát triển Web. Tôi cũng điều hành một kênh YouTube mang tên DevLeonardo, hẹn gặp lại bạn ở đó!

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào