세션을 상태에 추가하기

로그인 과정을 완료하려면 사용자가 로그인했음을 반영하기 위해 앱 상태를 세션으로 업데이트해야 합니다.

앱 상태 업데이트

먼저 사용자가 로그인했음을 나타내도록 애플리케이션 상태를 업데이트합니다. 이 상태를 Login 컨테이너에 저장하고 싶을 수 있지만, 이 상태를 여러 곳에서 사용할 것이므로 상태를 상위로 끌어올리는 것이 합리적입니다. 가장 논리적인 위치는 App 컴포넌트입니다.

사용자의 로그인 상태를 저장하기 위해 src/App.tsxuseState 훅을 추가합니다.

Change indicator App 컴포넌트 함수 상단에 다음을 추가합니다.

const [isAuthenticated, userHasAuthenticated] = useState(false);

Change indicator 그리고 이를 임포트합니다.

import { useState } from "react";

이 코드는 isAuthenticated 상태 변수를 false로 초기화합니다. 즉, 사용자가 로그인하지 않은 상태입니다. userHasAuthenticated를 호출하면 이 상태를 업데이트할 수 있습니다. 하지만 Login 컨테이너가 이 메서드를 호출하려면 이 메서드의 참조를 전달해야 합니다.

세션을 Context에 저장하기

세션 관련 정보를 모든 컨테이너에 전달해야 합니다. 이를 prop으로 전달하면 각 컴포넌트마다 수동으로 전달해야 하기 때문에 번거로울 수 있습니다. 대신 React Context를 사용해 보겠습니다.

우리 앱 전체에서 사용할 컨텍스트를 만들겠습니다.

Change indicator packages/frontend/ React 디렉토리 안에 src/lib/ 디렉토리를 생성합니다.

$ mkdir src/lib/

이 디렉토리는 모든 공통 코드를 저장하는 데 사용됩니다.

Change indicator src/lib/contextLib.ts 파일을 생성하고 아래 내용을 추가합니다.

import { createContext, useContext } from "react";

export interface AppContextType {
  isAuthenticated: boolean;
  userHasAuthenticated: React.Dispatch<React.SetStateAction<boolean>>;
}

export const AppContext = createContext<AppContextType>({
  isAuthenticated: false,
  userHasAuthenticated: useAppContext,
});

export function useAppContext() {
  return useContext(AppContext);
}

이 간단한 코드는 두 가지를 생성하고 내보냅니다:

  1. createContext API를 사용해 앱의 새로운 컨텍스트를 생성합니다.
  2. useContext React Hook을 사용해 컨텍스트에 접근합니다.

컨텍스트가 어떻게 동작하는지 잘 모르더라도 걱정하지 마세요. 사용해 보면 더 이해가 될 것입니다.

Change indicator src/App.tsx 파일의 헤더 부분에 새로운 앱 컨텍스트를 임포트합니다.

import { AppContext, AppContextType } from "./lib/contextLib";

이제 세션을 컨텍스트에 추가하고 컨테이너에 전달해 보겠습니다:

Change indicator src/App.tsxreturn 문에서 Routes 컴포넌트를 감싸줍니다.

<Routes />

Change indicator 이렇게 변경합니다.

<AppContext.Provider
  value={{ isAuthenticated, userHasAuthenticated } as AppContextType}
>
  <Routes />
</AppContext.Provider>

React Context는 두 부분으로 구성됩니다. 첫 번째는 Provider입니다. 이는 React에게 Context Provider 안에 있는 모든 자식 컴포넌트가 우리가 넣은 것에 접근할 수 있어야 한다고 알려줍니다. 이 경우 우리는 다음 객체를 넣습니다:

{
  isAuthenticated, userHasAuthenticated;
}

Context를 사용하여 상태 업데이트하기

Context API의 두 번째 부분은 컨슈머(consumer)입니다. 이를 src/containers/Login.tsx의 Login 컨테이너에 추가하겠습니다.

Change indicator export default function Login() { 줄 아래에 훅을 추가합니다.

const { userHasAuthenticated } = useAppContext();

Change indicator 그리고 src/containers/Login.tsx의 헤더 부분에서 이를 임포트합니다.

import { useAppContext } from "../lib/contextLib";

이 코드는 React에게 여기서 앱 컨텍스트를 사용하고 싶으며, userHasAuthenticated 함수를 사용할 수 있게 해달라고 알려줍니다.

Change indicator 마지막으로, src/containers/Login.tsx에서 alert('Logged in'); 줄을 다음 코드로 대체합니다.

userHasAuthenticated(true);

로그아웃 버튼 만들기

이제 사용자가 로그인하면 로그아웃 버튼을 표시할 수 있습니다. src/App.tsx에서 다음 부분을 찾아보세요.

<LinkContainer to="/signup">
  <Nav.Link>Signup</Nav.Link>
</LinkContainer>
<LinkContainer to="/login">
  <Nav.Link>Login</Nav.Link>
</LinkContainer>

Change indicator 그리고 이를 다음 코드로 대체하세요:

{isAuthenticated ? (
    <Nav.Link onClick={handleLogout}>Logout</Nav.Link>
  ) : (
    <>
      <LinkContainer to="/signup">
        <Nav.Link>Signup</Nav.Link>
      </LinkContainer>
      <LinkContainer to="/login">
        <Nav.Link>Login</Nav.Link>
      </LinkContainer>
    </>
  )}

<> 또는 프래그먼트 컴포넌트는 플레이스홀더 컴포넌트로 생각할 수 있습니다. 사용자가 로그인하지 않은 경우 두 개의 링크를 렌더링하려면 이를 단일 컴포넌트(예: div)로 감싸야 합니다. 하지만 프래그먼트 컴포넌트를 사용하면 두 링크가 이 컴포넌트 안에 있지만 추가 HTML을 렌더링하지 않도록 React에 알립니다.

Change indicator 그리고 src/App.tsxreturn 문 위에 handleLogout 메서드를 추가하세요.

function handleLogout() {
  userHasAuthenticated(false);
}

이제 브라우저로 이동하여 Secure Our Serverless APIs 챕터에서 생성한 관리자 자격 증명으로 로그인해 보세요. 로그아웃 버튼이 즉시 나타나는 것을 확인할 수 있습니다.

로그인 상태 업데이트 스크린샷

이제 페이지를 새로고침하면 다시 로그아웃 상태가 됩니다. 이는 브라우저 세션에서 상태를 초기화하지 않기 때문입니다. 다음으로 이를 어떻게 처리하는지 살펴보겠습니다.