1. 로그인

로그인은 사용자의 username(또는 email)과 password를 백엔드로 전송해서

Access Token(여기서는 JWT를 사용)를 얻는다.

이렇게 얻은 Access Token을 관리하는 방법은 여러 가지가 있지만, 여기서는 usehooks-ts의

useLocalStorage를 사용해서 전역적으로 동기화한다.

  1. LoginFormStore를 이용해 로그인한다. 로그인에 성공하면 accessToken을 발급받는다. 로컬 스토리지에 set하는 것 까지 이뤄진다.

  2. useAccessToken 으로 accessToken을 ApiService 내부에 저장하고 매 요청마다 첨부한다.

LoginFormStore.ts

import { singleton } from "tsyringe";
import { Action, Store } from "usestore-ts";
import { apiService } from "../services/ApiService";

@singleton()
@Store()
export default class LoginFormStore {
  email = "";

  password = "";

  error = false;

  accessToken = "";

  get valid() {
    return this.email.includes("@") && !!this.password;
  }

  @Action()
  changeEmail(email: string) {
    this.email = email;
  }

  @Action()
  changePassword(password: string) {
    this.password = password;
  }

  @Action()
  private setAccessToken(accessToken: string) {
    this.accessToken = accessToken;
  }

  @Action()
  private setError() {
    this.error = true;
  }

  @Action()
  reset() {
    this.email = "";
    this.password = "";
    this.error = false;
    this.accessToken = "";
  }

  async login() {
    try {
      const accessToken = await apiService.login({
        email: this.email,
        password: this.password,
      });
      this.setAccessToken(accessToken);
    } catch (e) {
      this.setError();
    }
  }
}

useAccessToken

import { useEffect } from "react";
import { useLocalStorage } from "usehooks-ts";
import { apiService } from "../services/ApiService";

export default function useAccessToken() {
  const [accessToken, setAccessToken] = useLocalStorage("accessToken", "");

  useEffect(() => {
    apiService.setAccessToken(accessToken);
  }, [accessToken]);

  return { accessToken, setAccessToken };
}

routes.test.tsx 에서 로그인 test

context("when the current path is “/login", () => {
  it("renders the login page", async () => {
    renderRouter("/login");

    screen.getByRole("heading", { name: "로그인" });

    fireEvent.change(screen.getByLabelText("E-mail"), {
      target: { value: "tester@example.com" },
    });

    fireEvent.change(screen.getByLabelText("Password"), {
      target: { value: "password" },
    });

    fireEvent.click(screen.getByRole("button", { name: "로그인" }));

    await waitFor(() => {
      screen.getByText(/Orders/);
      screen.getByText(/Cart/);
      screen.getByText(/Logout/);
    });
  });
});

useAccessToken 훅을 이용해 손쉽게 로그인 여부를 알 수 있다.

const Container = styled.div`
  margin-bottom: 2rem;
  line-height: 1.8;
`;

export default function AddToCartForm() {
  const { accessToken } = useAccessToken(); //

  if (!accessToken) {
    return (
      <Container>
        {/* 주문하려면 <Link to="/login?redirect_to=/productfsd">로그인</Link>  원래 있던 주소로 돌아가는거*/}
        주문하려면 <Link to="/login">로그인</Link>
        하세요
      </Container>
    );
  }

  return (
    <Container>
      <Options />
      <Quantity />
      <Price />
      <SubmitButton />
    </Container>
  );
}

Last updated