StudyForYou / ouahhan-typescript-with-react

우아한 타입스크립트 with 리액트 스터디 레포 🧵
4 stars 0 forks source link

#32 [10장_1] 다음 컴포넌트에 타입스크립트와 Context API를 적용해주세요~! #50

Open drizzle96 opened 2 months ago

drizzle96 commented 2 months ago

❓문제

다음 컴포넌트에 타입스크립트와 Context API를 적용해주세요~!

import { useState } from 'react'

const App = () => {
  const [user, setUser] = useState(null)

  const login = (username) => {
    setUser({ name: username })
  }

  const logout = () => {
    setUser(null)
  }

  return (
    <div>
      <Navbar user={user} logout={logout} />
      <MainContent user={user} login={login} />
    </div>
  )
}

export default App
const Navbar = ({ user, logout }) => {
  return (
    <nav>
      {user ? (
        <>
          <span>Welcome, {user.name}</span>
          <button onClick={logout}>Logout</button>
        </>
      ) : (
        <span>Please log in</span>
      )}
    </nav>
  )
}

export default Navbar
const MainContent = ({ user, login }) => {
  return (
    <div>
      {user ? (
        <h1>Welcome back, {user.name}!</h1>
      ) : (
        <Login login={login} />
      )}
    </div>
  )
}

export default MainContent
const Login = ({ login }) => {
  const [username, setUsername] = useState('')

  const handleLogin = () => {
    login(username)
  }

  return (
    <div>
      <input
        type="text"
        placeholder="Username"
        value={username}
        onChange={(e) => setUsername(e.target.value)}
      />
      <button onClick={handleLogin}>Login</button>
    </div>
  )
}

export default Login

🎯답변

qooktree1 commented 1 month ago

검색했습니다...

// Context API 정의 Component
// AuthContext.tsx
import React, { createContext, useContext, useState, ReactNode } from 'react';

interface UserType {
    name: string;
}

interface AuthContextType {
    user: UserType | null;
    login: (username: string) => void;
    logout: () => void;
}

const AuthContext = createContext<AuthContextType | undefined>(undefined);

export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
  const [user, setUser] = useState<UserType | 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('Error');
  return context;
};

const App: React.FC = () => { return (

); };

export default App;


- Navbar.tsx
```tsx
import React from 'react';
import { useAuth } from './AuthContext';

const Navbar: React.FC = () => {
  const { user, logout } = useAuth();

  return (
    <nav>
      {user ? (
        <>
          <span>Welcome, {user.name}</span>
          <button onClick={logout}>Logout</button>
        </>
      ) : (
        <span>Please log in</span>
      )}
    </nav>
  );
};

export default Navbar;

const MainContent: React.FC = () => { const { user, login } = useAuth();

return (

{user ? (

Welcome back, {user.name}!

) : ( )}

); };

export default MainContent;


- Login.tsx
```tsx
import React, { useState } from 'react';

interface LoginProps {
  login: (username: string) => void;
}

const Login: React.FC<LoginProps> = ({ login }) => {
  const [username, setUsername] = useState<string>('');

  const handleLogin = () => {
    login(username);
  };

  return (
    <div>
      <input
        type="text"
        placeholder="Username"
        value={username}
        onChange={(e) => setUsername(e.target.value)}
      />
      <button onClick={handleLogin}>Login</button>
    </div>
  );
};

export default Login;
drizzle96 commented 1 month ago

[컨텍스트 API 사용 과정 3단계]

  1. createContext를 통한 Context 생성하기
  2. Context Provider를 통한 Context 제공하기
  3. useContext를 통한 Context 사용하기

[1단계] Context 생성하기

// authContext.tsx
import { FC, ReactElement, createContext, useContext, useState } from 'react'

type User = {
  name: string
}

type AuthContextType = {
  user: User | null
  login: (username: string) => void
  logout: () => void
}

const AuthContext = createContext<AuthContextType>({
  user: null,
  login: () => { },
  logout: () => { },
})

const AuthProvider: FC<{ children: ReactElement }> = ({ children }) => {
  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>
  )
}

const useAuth = () => {
  const context = useContext(AuthContext)
  if (context === undefined) {
    throw new Error('useAuth must be used within an AuthProvider')
  }
  return context
}

export { useAuth, AuthProvider }

[2단계] Provider를 통한 Context 제공하기

// App.tsx
import { AuthProvider } from './authContext'

const App = () => {
  return (
    <AuthProvider>
      <div>
        <Navbar />
        <MainContent />
      </div>
    </AuthProvider>
  )
}

export default App

[3단계] useContext를 통한 Context 사용하기

// Navbar.tsx
import { useAuth } from './authContext'

const Navbar: React.FC = () => {
  const { user, logout } = useAuth();

  return (
    <nav>
      {user ? (
        <>
          <span>Welcome, {user.name}</span>
          <button onClick={logout}>Logout</button>
        </>
      ) : (
        <span>Please log in</span>
      )}
    </nav>
  );
};

export default Navbar
// MainContent.tsx
import { useAuth } from './authContext'

const MainContent: React.FC = () => {
  const { user } = useAuth();

  return (
    <div>
      {user ? (
        <h1>Welcome back, {user.name}!</h1>
      ) : (
        <Login />
      )}
    </div>
  );
};

export default MainContent
// Login.tsx
import { login } from './authContext'

const Login: React.FC = () => {
  const [username, setUsername] = useState('');
  const { login } = useAuth();

  const handleLogin = () => {
    login(username);
  };

  return (
    <div>
      <input
        type="text"
        placeholder="Username"
        value={username}
        onChange={(e) => setUsername(e.target.value)}
      />
      <button onClick={handleLogin}>Login</button>
    </div>
  );
};

export default Login