/components
├── AuthContext.js (Context를 생성하고 Provider 정의)
├── LoginButton.js (Context를 사용하는 컴포넌트)
├── UserInfo.js (Context를 사용하는 또 다른 컴포넌트)
└── LogoutButton.js (로그아웃 기능을 제공하는 컴포넌트)
이런 파일 구조들이 있다면, 코드들은 아래와 같습니다.
//AuthContext.js
import { createContext, useContext, useState } from 'react';
// 1. Context 생성
const AuthContext = createContext();
// 2. Provider 정의
export function AuthProvider({ children }) {
const [user, setUser] = useState(null);
// 로그인 함수
const login = (username) => {
setUser({ name: username });
};
// 로그아웃 함수
const logout = () => {
setUser(null);
};
return (
<AuthContext.Provider value={{ user, login, logout }}>
{children}
</AuthContext.Provider>
);
}
// 3. Context 값을 쉽게 가져오는 Hook
export function useAuth() {
return useContext(AuthContext);
}
//LoginButton.js
import { useAuth } from './AuthContext';
export default function LoginButton() {
const { login } = useAuth();
return (
<button onClick={() => login('홍길동')}>
Login
</button>
);
}
//UserInfo.js
import { useAuth } from './AuthContext';
export default function UserInfo() {
const { user } = useAuth();
if (!user) {
return <p>유저정보가 없습니다.</p>;
}
return (
<div>
<p>{user.name}!</p>
</div>
);
}
//LogoutButton.js
import { useAuth } from './AuthContext';
export default function LogoutButton() {
const { logout } = useAuth();
return (
<button onClick={logout}>
Logout
</button>
);
}
// pages/index.js
import LoginButton from '@/components/LoginButton';
import UserInfo from '@/components/UserInfo';
import LogoutButton from '@/components/LogoutButton';
export default function Home() {
return (
<div>
<UserInfo />
<LoginButton />
<LogoutButton />
</div>
);
}
import { AuthProvider } from '../components/AuthContext';
export default function MyApp({ Component, pageProps }) {
return (
<AuthProvider>
<Component {...pageProps} />
</AuthProvider>
);
}
사실 위 코드들은 제가 타입스크립트로 변환하기 위해서 GPT에게 문제를 내달라고 했습니다.
그래서 지금부터 코드는 Next.js를 Typescript로 변환하는 작업을 할 것입니다. 맨 아래에 정답을 남겨놓겠습니다.
바로 아래 코드는 정답이 아니고, 제가 공부한대로 작성하고 GPT에게 검사를 맡을 예정인 코드입니다.
//AuthContext.tsx
import { createContext, useContext, useState, ReactNode } from 'react';
type User = {
name: string;
}
type AuthContextType = {
user: User | null;
login: (username: string) => void;
logout: () => void;
};
const AuthContext = createContext<AuthContextType>();
interface AuthProviderProps {
children: ReactNode;
}
export function AuthProvider({ children }: AuthProviderProps) {
const [user, setUser] = useState<User | null>(null);
const login = (username: string) => {
setUser({ name: username });
};
const logout = () => {
setUser(null);
};
return (
<AuthContext.Provider value={{ user, login, logout }}>
{children}
</AuthContext.Provider>
);
}
export const useAuth = (): AuthContextType => {
return useContext(AuthContext);
}
import { AuthProvider } from '../components/AuthContext';
export default function MyApp({ Component, pageProps } : AppProps) {
return (
<AuthProvider>
<Component {...pageProps} />
</AuthProvider>
);
}
사실 vscode로 빨간줄 확인하면서 해야하는데, 무작정 시도해봅니다..ㅎ
결과는...
1. createContext 기본값 처리
createContext<AuthContextType>()에서 기본값을 undefined로 설정해야 합니다. 그렇지 않으면 useContext를 사용할 때 AuthContext가 undefined일 경우 TypeScript에서 오류가 발생할 수 있습니다.
( 수정: 오류는 런타임 오류와 컴파일 타임 타입 에러가 있습니다.
Provider를 사용하지 않았을 때는 런타임 오류가 일어나는 것이고,
undefined를 작성하지 않았을 때는 undefined일 가능성의 이유로 컴파일 단계에서 타입 오류를 지정합니다.
따라서 이 부분은 컴파일 타입 에러입니다!)
수정 필요: createContext에 기본값을 명시적으로 설정해야 합니다.
2. useContext에서 타입 처리
createContext에 기본값을 undefined로 설정하고, useContext를 사용할 때 context가 undefined일 경우를 처리해야 합니다. 그렇지 않으면 컴포넌트 외부에서 AuthContext를 사용할 때 오류가 발생할 수 있습니다.
...^^ 정답은 아래
import { createContext, useContext, useState, ReactNode } from 'react';
// 1. User 타입 정의
type User = {
name: string;
}
// 2. AuthContextType 정의
type AuthContextType = {
user: User | null;
login: (username: string) => void;
logout: () => void;
};
// 3. 기본값을 `undefined`로 설정하여 context가 없을 때 오류를 방지
const AuthContext = createContext<AuthContextType | undefined>(undefined);
// 4. AuthProviderProps 정의
interface AuthProviderProps {
children: ReactNode;
}
// 5. AuthProvider 컴포넌트 정의
export function AuthProvider({ children }: AuthProviderProps) {
const [user, setUser] = useState<User | null>(null);
const login = (username: string) => {
setUser({ name: username });
};
const logout = () => {
setUser(null);
};
return (
<AuthContext.Provider value={{ user, login, logout }}>
{children}
</AuthContext.Provider>
);
}
export const useAuth = (): AuthContextType => {
const context = useContext(AuthContext);
if (!context) {
throw new Error('useAuth must be used within an AuthProvider');
}
return context;
};
거의 다 undefined 문제였습니다..ㅎ undefined에 대해서 확실하게 개념 잡고 가야하겠습니다!
'추가공부' 카테고리의 다른 글
고급 프로젝트에서 사용(도전)할 것 -1 (2) | 2024.12.19 |
---|---|
모르는 거 확실하게 알고 넘어가기! (4) | 2024.12.17 |