π€ 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
μΈν°νμ΄μ€λ₯Ό νμ₯νμ¬ νκ²½ λ³μμ νμ μ μ μνλ€- μ΄λ κ² νλ©΄ νκ²½ λ³μλ₯Ό μ¬μ©ν λ νμ 체ν¬κ° κ°λ₯νλ€
- νμ νκ²½ λ³μκ° λλ½λμμ λ μ»΄νμΌ μμ μ μ€λ₯λ₯Ό λ°κ²¬ν μ μλ€
μ£Όμ κ°μ ν¨κ³Ό
- νμ
μμ μ± ν₯μ
- μ»΄νμΌ μμ μ νμ κ΄λ ¨ μ€λ₯λ₯Ό λ°κ²¬ν μ μλ€
- λ°νμ μλ¬λ₯Ό μ€μΌ μ μλ€
- μ½λ μλμμ± μ§μ
- IDEμμ λ μ νν μλμμ±μ μ 곡νλ€
- μ½λ μμ± μλκ° ν₯μλλ€
- μ€μ λ°©μ§
- νμ props λλ½μ λ°©μ§νλ€
- μλͺ»λ νμ μ λ°μ΄ν°λ₯Ό μ λ¬νλ κ²μ λ°©μ§νλ€
- μ½λ κ°λ
μ± ν₯μ
- νμ μ μλ₯Ό ν΅ν΄ μ½λμ μλλ₯Ό λͺ νν ν μ μλ€
- λ€λ₯Έ κ°λ°μκ° μ½λλ₯Ό μ΄ν΄νκΈ° μ¬μμ§λ€
- 리ν©ν λ§ μ μμ μ± ν₯μ
- νμ μμ€ν μ ν΅ν΄ 리ν©ν λ§ μ λ°μν μ μλ μ€λ₯λ₯Ό 미리 λ°κ²¬ν μ μλ€
- μ½λ λ³κ²½ μ μν₯ λ²μλ₯Ό νμ νκΈ° μ¬μμ§λ€
- λ°νμ μλ¬ μ¬μ λ°©μ§
- νμ 체ν¬λ₯Ό ν΅ν΄ λ°νμμ λ°μν μ μλ μ€λ₯λ₯Ό 미리 λ°©μ§ν μ μλ€
- λλ²κΉ μκ°μ μ€μΌ μ μλ€
μ΄λ¬ν λ³κ²½μ¬νλ€λ‘ μΈν΄ μ½λμ νμ§κ³Ό μ μ§λ³΄μμ±μ΄ ν¬κ² ν₯μλλ€!
λ°μν