[11주차 Day5] 타입스크립트 기반 리액트

반 히·2024년 5월 10일

데브코스

목록 보기
27/58
post-thumbnail

💡 컴포넌트


📌 클래스형 컴포넌트

  • 리액트 초기 버전에서 주로 사용했던 컴포넌트 방식
// ClassCom.tsx
import { Component } from "react";

class ClassCom extends Component {
    render() {
        return (
            <div>
                클래스형 컴포넌트
            </div>
        );
    }
}

export default ClassCom;
//App.tsx
import React from 'react';
import logo from './logo.svg';
import './App.css';
import ClassCom from './ClassCom';

function App() {
  let name = "리액트";
  return (
    <div className="container">
      <ClassCom></ClassCom>
    </div>
  );
}

export default App;

  • 리액트에서는 클래스형 컴포넌트를 만들 때 반드시 Component라는 클래스를 상속해야 하므로 import 먼저 해줌
  • render 메소드 : return 하위에 있는 jsx 코드를 반환함
  • 다른 파일에서 이 컴포넌트를 사용하기 위해서 exports 해주어야 함.
  • 메인 파일에서 클래스형 컴포넌트를 작성한 파일을 import하기.

📌 함수형 컴포넌트

  • 최근 리액트가 권장하는 컴포넌트 방식
  • 가독성과 코드의 형식면에서 클래스형 컴포넌트보다 간단함
// FuncCom.tsx
import React from 'react';

const FuncCom = () =>
// function FuncCom()
{
    return(
        <div>
            함수형 컴포넌트
        </div>
    );
}

export default FuncCom;
import React from 'react';
import logo from './logo.svg';
import './App.css';
import ClassCom from './ClassCom';
import FuncCom from './FuncCom';

function App() {
  let name = "리액트";
  return (
    <div className="container">
      <ClassCom></ClassCom>
      <FuncCom></FuncCom>
    </div>
  );
}

export default App;

  • 클래스형 컴포넌트와 달리 render 필요없이 바로 return을 통해 렌더링 가능
  • 다른 파일에서 사용하기 위해 exports 해주어야 함.
  • 메인 파일에서 import하여 사용함.
  • 클래스형 컴포넌트의 render 부분을 간소화 시켜서 개선함.
  • 클래스형 컴포넌트보다는 함수형 컴포넌트를 사용하도록 권장함

💡 state 사용해보기


📌 변수 이용하여 데이터 바인딩

const TodoList : React.FC = () => {
    const title : string = "오늘 할 일";
    return(
        <div className='container'>
            <h1>{title}</h1>
        </div>
    );
}
  • React.FC
    • 리액트 컴포넌트를 정의할 때 타입스크립트에서 사용함.
    • Function Component의 약자임. 함수형 컴포넌트를 정의할 때 리액트에서 사용함.
    • 코드를 조금 더 명확하고 가독성을 높여주기 위해서 사용함

📌 state 이용하여 데이터 바인딩

import React, { useState } from 'react';

const TodoList : React.FC = () => {
    const title : string = "오늘 할 일";
    const [todos] = useState(['공부하기', '잠자기', '미팅하기']);
    return(
        <div>
            <h1>{title}</h1>
            <p></p>
            <div className='container'>
                <ul>
                    <li>{todos[0]}</li>
                    <li>{todos[1]}</li>
                    <li>{todos[2]}</li>
                </ul>
            </div>
        </div>
    );
}

export default TodoList;
  • react에서는 일반 변수가 아니라 state를 사용해서 데이터를 저장함.
  • state(상태) : 데이터의 상태를 의미함.
    • 데이터를 동적으로 감시해서 데이터가 변경이 되면 즉시 화면에 반영하겠다는 의미로 사용함
    • 일반 변수를 사용하면 상태 관리가 안 됨.
    • state를 사용하게 되면 react 내부에서 상태 관리를 할 수 있음
  • useState라는 함수 이용.
    • use로 시작되는 리액트에서 기본적으로 제공해주는 Hook 중의 하나
  • 다량의 변수를 배열의 형태로 관리할 수 있음
const [todos, setTodos] = useState(['공부하기', '잠자기', '미팅하기']);
  • state 변수의 경우, 리액트에서는 직접적으로 접근해서 데이터를 변경하지 않고 별도의 변경함수를 사용하라고 권고하고 있음
    • 변경 함수를 두 번째 요소에 추가 가능
    • 항상 state를 사용할 때 항상 한 쌍으로 사용
    • 첫 번째 부분은 state에 데이터가 저장되고, 두 번째 부분은 변경함수가 들어가 있음
  • 클래스의 구성 요소 : 멤버변수 + 멤버 함수
    • 캡슐화 철학 때문. 멤버 변수를 보호하기 위해
    • 이와 마찬가지임
  • todos라는 데이터를 변경할 때는 setTodos라는 함수를 이용해서 변경해야 함

💡 구조 할당 분해


구조 분해 할당을 이용해서 직접적으로 데이터를 변수에 넣을 수 있음

const colors = ['red', 'green', 'blue'];
const [f, s, t] = colors;
console.log(f);	// red 출력
console.log(s);	// green 출력
console.log(t);	// blue 출력

어떤 특정 데이터를 하나의 객체로 넘겼다면 그 객체를 분해해서 넘길 수 있음.
객체도 가능함

const person = {
  name : 'lim',
  age : 23,
  city : 'seoul'
};
const {name, age, city} = person;
console.log(name);	//lim 출력
console.log(age);	//23 출력
console.log(city);	//seoul 출력
// 구조 분해 할당 
const [todos, setTodos] = useState<string[]>(['공부하기', '잠자기', '미팅하기']);


💡 데이터 반복 처리하기


📌 map 이용

import React from 'react';

const MapTest = () => {
    const fruits = ['apple', 'banana', 'orange'];

    return(
        <div>
            <h2>과일</h2>
            <ul>
                {
                    fruits.map((fruit, index) => (
                        <li key={index}>{fruit}</li>
                    ))
                }
            </ul>
        </div>
    );
}

export default MapTest;

  • map 함수
    • 첫 번째 요소 : 반복하면서 각각의 요소들을 차례차례 전달받는 변수
    • 두 번째 요소(index) : 0부터 1씩 증가하는 정수
  • map을 사용할 때 각각의 요소에 key라는 속성을 설정해주어야 함
    • 동적으로 element를 생성해서 렌더링함.
    • 리액트는 컴포넌트 배열을 렌더링할 때 각각의 element 요소에 대해 고유한 키 값을 지정해줌
    • 리액트가 컴포넌트의 변화를 효율적으로 추적하고 관리하기 위해서 각각의 다른 고유한 인덱스를 key값으로 넣어줌
    • 필수는 아니고 권장임.
type Todo = {
    id : number;
    text : string;
    isChecked : boolean;
};

const TodoList : React.FC = () => {
    const title : string = "오늘 할 일";

    // 구조 분해 할당 
    const [todos, setTodos] = useState<Todo[]>([
        {id : 1, text : '공부하기', isChecked : false},
        {id : 2, text : '잠자기', isChecked : false},
        {id : 3, text : '미팅하기', isChecked : false}
    ]);

    return(
        <div>
            <h1>{title}</h1>
            <p></p>
            <div className='container'>
                <div className='board'>
                    <ul>
                        {
                            todos.map((todo, index) => (
                                <li key={index}>{todo.text}</li>
                            ))
                        }
                    </ul>
                </div>
            </div>
        </div>
    );
}
  • 사용자 정의 type 설정 후 map 함수를 통해 데이터 반복 처리.

💡 체크박스 기능 추가


<ul>
	{
		todos.map((todo, index) => (
			<li key={todo.id}>
				<input type = "checkbox"
				onChange={()=> {
					handleCheckedChange(todo.id);
				}}></input>
				<span>
					{
						todo.isChecked ?
						<del>{todo.text}</del>
						: <span>{todo.text}</span>
					} 
				</span>
			</li>
		))
}
</ul>

체크박스의 기능을 추가하기 위해 이벤트 함수 추가.
체크하면 취소선이 그어지도록..

const [todos, setTodos] = useState<Todo[]>([
	{id : 1, text : '공부하기', isChecked : false},
	{id : 2, text : '잠자기', isChecked : false},
	{id : 3, text : '미팅하기', isChecked : false}
]);

const handleCheckedChange = (itemId : number) => {
	setTodos((prevItems) => 
		prevItems.map((item) => 
			item.id === itemId ? {...item, isChecked : !item.isChecked } : item
		)
	)
}

만약 체크되면 해당 아이템의 isChecked를 바꾼다. (true는 false로 false는 true로)

0개의 댓글