🐀 Web/🌐 React

λ¦¬μ•‘νŠΈ μžλ°”μŠ€ν¬λ¦½νŠΈ -> νƒ€μž…μŠ€ν¬λ¦½νŠΈλ‘œ λ§ˆμ΄κ·Έλ ˆμ΄μ…˜ ν•˜κΈ°!

chamroro 2025. 4. 6. 16:18

1. μ»΄ν¬λ„ŒνŠΈ μ„ μ–Έ 방식

// κΈ°μ‘΄ JS
const Dashboard = () => {
  // ...
}
// λ³€ν™˜λœ TSX
const Dashboard: React.FC = () => {
  // ...
}
  • React.FC (Function Component) νƒ€μž…μ„ λͺ…μ‹œμ μœΌλ‘œ μ„ μ–Έν•˜μ—¬ TypeScriptμ—κ²Œ 이 μ»΄ν¬λ„ŒνŠΈκ°€ React μ»΄ν¬λ„ŒνŠΈμž„μ„ μ•Œλ €μ€€λ‹€
  • μ΄λ ‡κ²Œ ν•˜λ©΄ μ»΄ν¬λ„ŒνŠΈμ˜ props νƒ€μž…μ„ μžλ™μœΌλ‘œ μΆ”λ‘ ν•  수 있으며, React κ΄€λ ¨ νƒ€μž… 체크도 κ°€λŠ₯ν•˜λ‹€
  • μ΅œμ‹  Reactμ—μ„œλŠ” React.FC λŒ€μ‹  React.ComponentType을 μ‚¬μš©ν•˜λŠ” κ²½μš°λ„ μžˆλ‹€

 

2. Props νƒ€μž… μ •μ˜

// κΈ°μ‘΄ JS
const CategoryEditor = ({ onClose }) => {
  // ...
}
// λ³€ν™˜λœ TSX
interface CategoryEditorProps {
  onClose: (value: boolean) => void;
}

const CategoryEditor: React.FC<CategoryEditorProps> = ({ onClose }) => {
  // ...
}
  • interfaceλ₯Ό μ‚¬μš©ν•˜μ—¬ μ»΄ν¬λ„ŒνŠΈμ˜ props νƒ€μž…μ„ λͺ…μ‹œμ μœΌλ‘œ μ •μ˜ν•œλ‹€
  • onClose ν•¨μˆ˜μ˜ λ§€κ°œλ³€μˆ˜μ™€ λ°˜ν™˜ νƒ€μž…μ„ λͺ…ν™•ν•˜κ²Œ μ§€μ •ν•  수 μžˆλ‹€
  • μ΄λ ‡κ²Œ ν•˜λ©΄ μ»΄ν¬λ„ŒνŠΈ μ‚¬μš© μ‹œ ν•„μš”ν•œ propsλ₯Ό λˆ„λ½ν•˜κ±°λ‚˜ 잘λͺ»λœ νƒ€μž…μ„ μ „λ‹¬ν•˜λŠ” 것을 λ°©μ§€ν•  수 μžˆλ‹€ 

 

3. μƒνƒœ(State) νƒ€μž… μ •μ˜

// κΈ°μ‘΄ JS
const [course, setCourse] = useState(null);
// λ³€ν™˜λœ TSX
const [course, setCourse] = useState<Course | null>(null);
  • useState 훅에 μ œλ„€λ¦­ νƒ€μž…μ„ μ‚¬μš©ν•˜μ—¬ μƒνƒœμ˜ νƒ€μž…μ„ λͺ…μ‹œν•œλ‹€
  • Course | null은 courseκ°€ Course νƒ€μž…μ΄κ±°λ‚˜ null일 수 μžˆμŒμ„ λ‚˜νƒ€λ‚Έλ‹€
  • μ΄λ ‡κ²Œ ν•˜λ©΄ μƒνƒœλ₯Ό μ‚¬μš©ν•  λ•Œ νƒ€μž… μ•ˆμ „μ„±μ΄ 보μž₯되며, IDE의 μžλ™μ™„μ„± κΈ°λŠ₯도 ν™œμš©ν•  수 μžˆλ‹€ 

 

4. 이벀트 ν•Έλ“€λŸ¬ νƒ€μž…

// κΈ°μ‘΄ JS
const handleSubmit = (e) => {
  e.preventDefault();
  // ...
}
// λ³€ν™˜λœ TSX
const handleSubmit = (e: React.FormEvent) => {
  e.preventDefault();
  // ...
}
  • 이벀트 ν•Έλ“€λŸ¬μ˜ λ§€κ°œλ³€μˆ˜μ— React.FormEvent νƒ€μž…μ„ μ§€μ •ν•œλ‹€
  • μ΄λŠ” 폼 제좜 이벀트의 νƒ€μž…μ„ λͺ…ν™•νžˆ ν•˜μ—¬, 이벀트 객체의 속성에 μ•ˆμ „ν•˜κ²Œ μ ‘κ·Όν•  수 있게 ν•œλ‹€
  • λ‹€λ₯Έ 이벀트 νƒ€μž…μœΌλ‘œλŠ” React.MouseEvent, React.ChangeEvent 등이 μžˆλ‹€

 

5. styled-components νƒ€μž…

// κΈ°μ‘΄ JS
const Chip = styled.button`
  background-color: ${props => props.active ? "#007bff" : "white"};
`
// λ³€ν™˜λœ TSX
const Chip = styled.button<{ active: boolean }>`
  background-color: ${props => props.active ? "#007bff" : "white"};
`
  • styled-componentsμ—μ„œ props의 νƒ€μž…μ„ μ œλ„€λ¦­μœΌλ‘œ μ •μ˜ν•œλ‹€
  • active prop이 boolean νƒ€μž…μž„μ„ λͺ…μ‹œν•˜μ—¬, μ»΄ν¬λ„ŒνŠΈ μ‚¬μš© μ‹œ νƒ€μž… 체크가 κ°€λŠ₯ν•˜λ‹€
  • μ΄λ ‡κ²Œ ν•˜λ©΄ μŠ€νƒ€μΌ μ»΄ν¬λ„ŒνŠΈμ˜ props에 λŒ€ν•œ νƒ€μž… μ•ˆμ „μ„±μ΄ 보μž₯λœλ‹€ 

 

6. Redux κ΄€λ ¨ νƒ€μž… μ •μ˜

// κΈ°μ‘΄ JS
const dispatch = useDispatch();
const { categories } = useSelector(state => state.category);
// λ³€ν™˜λœ TSX
const dispatch = useAppDispatch();
const { categories } = useAppSelector((state: RootState) => state.category);
  • Redux의 dispatch와 useSelector에 νƒ€μž…μ„ μΆ”κ°€ν•˜μ—¬ νƒ€μž… μ•ˆμ „μ„±μ„ 보μž₯ν•œλ‹€
  • RootState νƒ€μž…μ„ μ‚¬μš©ν•˜μ—¬ 전체 Redux μƒνƒœμ˜ ꡬ쑰λ₯Ό λͺ…ν™•νžˆ ν•œλ‹€
  • μ»€μŠ€ν…€ 훅인 useAppDispatch와 useAppSelectorλ₯Ό μ‚¬μš©ν•˜μ—¬ νƒ€μž…μ΄ μ§€μ •λœ dispatch와 selectorλ₯Ό μ œκ³΅ν•œλ‹€ 

 

7. Firebase 데이터 νƒ€μž… μ •μ˜

// κΈ°μ‘΄ JS
const coursesData = coursesSnapshot.docs.map(doc => ({
  id: doc.id,
  ...doc.data()
}));
// λ³€ν™˜λœ TSX
const coursesData = coursesSnapshot.docs.map(doc => ({
  id: doc.id,
  ...doc.data()
})) as Course[];
  • Firebaseμ—μ„œ κ°€μ Έμ˜¨ 데이터에 Course νƒ€μž…μ„ λͺ…μ‹œμ μœΌλ‘œ μ§€μ •ν•œλ‹€
  • as Course[]λ₯Ό μ‚¬μš©ν•˜μ—¬ νƒ€μž… 단언(type assertion)을 μˆ˜ν–‰ν•œλ‹€
  • μ΄λ ‡κ²Œ ν•˜λ©΄ Firebase 데이터λ₯Ό μ‚¬μš©ν•  λ•Œ νƒ€μž… μ•ˆμ „μ„±μ΄ 보μž₯λœλ‹€ 

 

8. νƒ€μž… κ°€λ“œ μΆ”κ°€

// κΈ°μ‘΄ JS
filtered = selectedCat.courseDetails.filter(course => course != null);
// λ³€ν™˜λœ TSX
filtered = (selectedCat.courseDetails || []).filter((course): course is Course => course !== null);
  • νƒ€μž… κ°€λ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ null이 μ•„λ‹Œ Course 객체만 ν•„ν„°λ§ν•œλ‹€
  • course is CourseλŠ” νƒ€μž… κ°€λ“œλ‘œ, ν•„ν„°λ§λœ 배열이 Course[] νƒ€μž…μž„μ„ 보μž₯ν•œλ‹€
  • μ΄λ ‡κ²Œ ν•˜λ©΄ null 값을 μ•ˆμ „ν•˜κ²Œ μ²˜λ¦¬ν•  수 μžˆλ‹€ 

 

9. μΈν„°νŽ˜μ΄μŠ€ μ •μ˜ μΆ”κ°€

export interface Course {
  id: string;
  courseName: string;
  courseLength: number;
  description: string;
  locationInfo?: {
    latitude: number;
    longitude: number;
  };
}

export interface Category {
  id: string;
  title: string;
  courseIdList: string[];
  courseDetails?: (Course | null)[];
}
  • μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ μ‚¬μš©λ˜λŠ” μ£Όμš” 데이터 ꡬ쑰λ₯Ό μΈν„°νŽ˜μ΄μŠ€λ‘œ μ •μ˜ν•œλ‹€
  • ?λ₯Ό μ‚¬μš©ν•˜μ—¬ 선택적 속성을 ν‘œμ‹œν•œλ‹€
  • μΈν„°νŽ˜μ΄μŠ€λ₯Ό exportν•˜μ—¬ λ‹€λ₯Έ νŒŒμΌμ—μ„œ μž¬μ‚¬μš©ν•  수 있게 ν•œλ‹€ 

 

10. ν™˜κ²½ λ³€μˆ˜ νƒ€μž… μ •μ˜

// κΈ°μ‘΄ JS
process.env.REACT_APP_FIREBASE_API_KEY
// λ³€ν™˜λœ TSX
declare global {
  namespace NodeJS {
    interface ProcessEnv {
      REACT_APP_FIREBASE_API_KEY: string;
      // ... λ‹€λ₯Έ ν™˜κ²½ λ³€μˆ˜λ“€
    }
  }
}
  • ProcessEnv μΈν„°νŽ˜μ΄μŠ€λ₯Ό ν™•μž₯ν•˜μ—¬ ν™˜κ²½ λ³€μˆ˜μ˜ νƒ€μž…μ„ μ •μ˜ν•œλ‹€
  • μ΄λ ‡κ²Œ ν•˜λ©΄ ν™˜κ²½ λ³€μˆ˜λ₯Ό μ‚¬μš©ν•  λ•Œ νƒ€μž… 체크가 κ°€λŠ₯ν•˜λ‹€
  • ν•„μˆ˜ ν™˜κ²½ λ³€μˆ˜κ°€ λˆ„λ½λ˜μ—ˆμ„ λ•Œ 컴파일 μ‹œμ μ— 였λ₯˜λ₯Ό λ°œκ²¬ν•  수 μžˆλ‹€ 

 

μ£Όμš” κ°œμ„  효과

  1. νƒ€μž… μ•ˆμ „μ„± ν–₯상
    • 컴파일 μ‹œμ μ— νƒ€μž… κ΄€λ ¨ 였λ₯˜λ₯Ό λ°œκ²¬ν•  수 μžˆλ‹€
    • λŸ°νƒ€μž„ μ—λŸ¬λ₯Ό 쀄일 수 μžˆλ‹€ 
  2. μ½”λ“œ μžλ™μ™„μ„± 지원
    • IDEμ—μ„œ 더 μ •ν™•ν•œ μžλ™μ™„μ„±μ„ μ œκ³΅ν•œλ‹€
    • μ½”λ“œ μž‘μ„± 속도가 ν–₯μƒλœλ‹€ 
  3. μ‹€μˆ˜ λ°©μ§€
    • ν•„μˆ˜ props λˆ„λ½μ„ λ°©μ§€ν•œλ‹€
    • 잘λͺ»λœ νƒ€μž…μ˜ 데이터λ₯Ό μ „λ‹¬ν•˜λŠ” 것을 λ°©μ§€ν•œλ‹€ 
  4. μ½”λ“œ 가독성 ν–₯상
    • νƒ€μž… μ •μ˜λ₯Ό 톡해 μ½”λ“œμ˜ μ˜λ„λ₯Ό λͺ…ν™•νžˆ ν•  수 μžˆλ‹€
    • λ‹€λ₯Έ κ°œλ°œμžκ°€ μ½”λ“œλ₯Ό μ΄ν•΄ν•˜κΈ° μ‰¬μ›Œμ§„λ‹€ 
  5. λ¦¬νŒ©ν† λ§ μ‹œ μ•ˆμ •μ„± ν–₯상
    • νƒ€μž… μ‹œμŠ€ν…œμ„ 톡해 λ¦¬νŒ©ν† λ§ μ‹œ λ°œμƒν•  수 μžˆλŠ” 였λ₯˜λ₯Ό 미리 λ°œκ²¬ν•  수 μžˆλ‹€
    • μ½”λ“œ λ³€κ²½ μ‹œ 영ν–₯ λ²”μœ„λ₯Ό νŒŒμ•…ν•˜κΈ° μ‰¬μ›Œμ§„λ‹€ 
  6. λŸ°νƒ€μž„ μ—λŸ¬ 사전 λ°©μ§€
    • νƒ€μž… 체크λ₯Ό 톡해 λŸ°νƒ€μž„μ— λ°œμƒν•  수 μžˆλŠ” 였λ₯˜λ₯Ό 미리 λ°©μ§€ν•  수 μžˆλ‹€
    • 디버깅 μ‹œκ°„μ„ 쀄일 수 μžˆλ‹€ 

μ΄λŸ¬ν•œ λ³€κ²½μ‚¬ν•­λ“€λ‘œ 인해 μ½”λ“œμ˜ ν’ˆμ§ˆκ³Ό μœ μ§€λ³΄μˆ˜μ„±μ΄ 크게 ν–₯μƒλœλ‹€! 

λ°˜μ‘ν˜•