React Context를 사용하지 않고 User정보를 각각의 React 컴포넌트에서 사용하기 위해서는
컴포넌트 간 User 정보를 주고 받는 작업이 매번 이루어진다.
그러나 React Context에서 User 정보를 관리하게 되면 컴포넌트 간 데이터를 주고 받을 필요 없이
로그인 후 언제든 React Context에서 User 정보를 사용 가능하다.

User 정보를 정의한 interface를 생성한다.
reddit-clone-app\client\src\types.tsx 파일을 생성하고 아래 내용을 입력한다.
export interface User {
username: string;
email: string;
createdAt: string;
updatedAt: string;
}
reddit-clone-app\client\src\context\auth.tsx 파일을 생성하고 아래 내용을 추가한다.
import { createContext, useContext, useReducer } from "react";
import { User } from "../types";
// React Context에서 갖고 있어야할 정보를 정의한 interface
interface State {
authenticated: boolean;
user: User | undefined;
loading: boolean;
}
// React Context에서 갖고 있어야할 기본 정보
const StateContext = createContext<State>({
authenticated: false,
user: undefined,
loading: true,
})
const DispatchContext = createContext<any>(null);
interface Action {
type: string;
payload: any;
}
// dispatch Process 04
// User 정보를 dispatch 시 전달된 type으로 동작을 구분
const reducer = (state:State, { type, payload }:Action) => {
switch (type) {
case "LOGIN":
return {
...state,
authenticated: true,
user: payload
}
case "LOGOUT":
return {
...state,
authenticated: false,
user: null
}
case "STOP_LOADING":
return {
...state,
loading: false
}
default:
throw new Error(`Unknown action type: ${type}`)
}
}
// Context에 있는 value(User 정보)를 다른 컴포넌트에서 사용하기 위해서는 Context Provider로 감싸줘야 한다.
// 다른 컴포넌트를 감싸기 위한 Context Provider: AuthProvider 를 정의.
export const AuthProvider = ({children}:{children: React.ReactNode}) => {
// dispatch Process 03
// User정보를 dispath 시 reducer 함수를 사용
const [state, defaultDispatch] = useReducer(reducer, {
user: null,
authenticated: false,
loading: true
})
// User정보 Dispatch 시 확인용 로그
console.log('state', state);
// dispatch Process 02
const dispatch = (type: string, payload?: any) => {
defaultDispatch({ type, payload })
}
/*
* 최상위 컴포넌트 _app.tsx에서 타 컴포넌트를 보여줄 때
* 아래와 같이 return 하도록 정의한다.
*/
return (
<DispatchContext.Provider value={dispatch}>
<StateContext.Provider value={state}>{children}</StateContext.Provider>
</DispatchContext.Provider>
)
}
// 다른 컴포넌트에서 StateContext, DispatchContext의 value를 사용할 수 있도록 export
export const useAuthState = () => useContext(StateContext);
// dispatch Process 01
export const useAuthDispatch = () => useContext(DispatchContext);
React 최상위 컴포넌트인 reddit-clone-app\client\src\pages\_app.tsx 파일에 아래 내용을 추가한다.
import { AuthProvider } from '../context/auth';
function MyApp({ Component, pageProps }: AppProps) {
Axios.defaults.baseURL = process.env.NEXT_PUBLIC_SERVER_BASE_URL + "/api";
// 추가된 내용
return <AuthProvider>
<Component {...pageProps} />
</AuthProvider>
}
reddit-clone-app\client\src\pages\login.tsx 파일에 아래 내용을 추가
...생략
const handleSubmit = async (event: FormEvent) => {
event.preventDefault();
try {
const res = await axios.post(
"/auth/login",
{
password,
username
},
{
withCredentials: true
}
);
// [추가 부분]
// 정상 로그인 유저정보 Context 저장
dispatch("LOGIN", res.data?.user);
// [추가 부분]
// 로그인 후 '/' 로 이동
router.push('/');
} catch (error: any) {
console.log(error);
setErrors(error.response.data || {})
}
};
...생략
state : {
"authenticated" : false
"loading" : true
"user" : null
}
state : {
"authenticated" : true,
"loading" : true,
"user" : {
"createdAt" : "2022-10-10T00:16:33.319Z",
"email" : "kdy95@inzent.com",
"id" : 7,
"password" : "$2a$06$4E9EgjZTq2uijDig1TTyl.queBrIVkmf2mmX6pORqQEgq0QdVtc1m",
"updatedAt" : "2022-10-10T00:16:33.319Z",
"username" : "doyun",
}
}