[2] react

Kim TaeHyeong·2026년 9월 25일

UMC

목록 보기
3/10

2

export default function App() {
    const movieTitle = "인터스텔라";
    const genre = "SF";
    const releasedDate = new Date('2014-11-06');
  
    return (
      <article className="movie-card">
        <h1>{movieTitle}</h1>
        <p>장르: {genre}</p>
        <p>개봉일: {releasedDate.toLocaleDateString()}</p>
      </article>
    );
  }

{}로 데이터 넣기 python의 f-string과 유사

3

function Header()
{
    return <h1>테스트 헤더</h1>;
}

function MovieList()
{
    return (
        <>
            <MovieCard />
            <MovieCard />
        </>
    );
    //Fragment이다. 여러 개를 하나의 객체로 묶어서 리턴
}

function MovieCard()
{
    return <h3>테스트 영화</h3>;
}
  
export default function App() {
    return (
        <main>
            <Header />
            <MovieList />
        </main>
    );
}

함수를 컴포넌트로 이용 가능. 단 대문자로 이용하셈.
return 할 때, 한 객체로 묵어서 나가야하기 때문에 <></> 같은 것으로 리턴

처럼 풀어서 ㄴㄴ

4

export interface MovieCardProp {
    title: string;
    releasedDate: string;
    isBookmarked: boolean;
};

//default 뜻: "이 파일의 메인 대표 선수"라는 뜻 (파일당 1개만 가능, 가져올 때 내 마음대로 이름 지정 가능)
//딱 하나

모듈화로 처리

import type { MovieCardProp } from "./components";
//이건 엄격함 때문에 추가됨

function MovieCard(prop: MovieCardProp)
{
    return (
        <article>
            <h1>{prop.title}</h1>
            <p>{prop.releasedDate}</p>
            <p>{prop.isBookmarked ? "북마크 됨" : "북마크하기"}</p>
        </article>
    );
}

function MovieList()
{
    return (
        <>
            <MovieCard 
                title="영화1"
                releasedDate="날짜1"
                isBookmarked={true}
            />
            <MovieCard 
                title="영화2"
                releasedDate="날짜2"
                isBookmarked={false}
            />
            <MovieCard 
                title="영화3"
                releasedDate="날짜3"
                isBookmarked={true}
            />
        </>
    )
}

export default function App()
{
    return  (
        <>
            <MovieList></MovieList>
            {/* <MovieList />랑 완전히 똑같다 */}
        </>
    );
}
/*
interface MovieCardProps {
    title: string;
    releasedDate: string;
    isBookmarked: boolean;
    test?: string; //이걸로 없어도 된다 표시 ts ㅇㅇ
}
function MovieCard(prop: MovieCardProps)
{
    return (
        <article>
            <h2>{prop.title}</h2>
            <p>{prop.releasedDate}</p>
            <p>{prop.isBookmarked ? "북마크됨" : "북마크 안 됨"}</p>
        </article>
    );
}
  
export default function App() {
    return (
        <>
            <MovieCard
                title="오디세이"
                releasedDate="2026.08.05"
                isBookmarked={true}
            />
            <MovieCard
                title="토이 스토리 5"
                releasedDate="2026.06.17"
                isBookmarked={false}
            />
        </>
    );
}
*/
/*  
function MovieCard({
    title,
    releasedDate: theDate,
    isBookmarked,
}: MovieCardProps)
{
    return (
        <article>
            <h2>{title}</h2>
            <p>{theDate}</p>
            <p>{isBookmarked ? "북마크됨" : "북마크 안 됨"}</p>
        </article>
    );
}
  
export default function App() {
    return (
        <>
            <MovieCard
                title="오디세이"
                releasedDate="2026.08.05"
                isBookmarked={true}
            />
            <MovieCard
                title="토이 스토리 5"
                releasedDate="2026.06.17"
                isBookmarked={false}
            />
        </>
    );
}
*/

/*
// ① 인터페이스(규칙 설계도)
interface MovieCardProps {
    title: string;          // 👈 'title'이라는 이름표 필수!
    releasedDate: string;   // 👈 'releasedDate' 필수!
    isBookmarked: boolean;  // 👈 'isBookmarked' 필수!
}
 
// ② 컴포넌트 (받는 곳)
function MovieCard({
    title,          // 👈 설계도에 있는 이름이랑 정확히 같아야 함
    releasedDate: 별명,   // 👈 (다른 이름으로 바꾸려면 별칭 써야 함)
    isBookmarked,
}: MovieCardProps)
{
    별명
}

export ... App
*/

Prop으로 리턴 형태 지정 가능

5

interface Movie {
    id : number,
    title : string,
    releasedDate : Date,
}

const movies : Movie[] = [
    {id: 1, title: "영화1", releasedDate: new Date("2026-09-22")},
    {id: 2, title: "영화2", releasedDate: new Date("2026-09-23")},
];

function MovieList()
{
    return (
        <ul>
            {movies.map((movie) => (
                <li key={movie.id}> {/* 나중에 id 쓰려고*/}
                    <h1>{movie.title}</h1>
                    <p>{movie.releasedDate.toLocaleDateString()}</p>
                    <p>id : {movie.id}</p>
                </li>
            ))}
        </ul>
    );
}

function MovieSection()
{
    return (
        <>
            {movies.length === 0 ? (<p>표시할 영화가 없어요.</p>) : (MovieList())}
        </>
    );
}

export default function App()
{
    return  (
        <>
            <MovieSection></MovieSection>
        </>
    );
}

map으로 반복하면서 출력

6

export default function App() {
    function handleClick() {
        alert("버튼을 클릭했어요.");
    }
  
    return (
        <button onClick={handleClick}>
            클릭하기
        </button>
    );
}

버튼 예제

import {useState} from "react";

export default function App()
{
    const [value, setValue] = useState(0);
    const MAX_VALUE = 5, MIN_VALUE = 0;

    function changeValue(updater : Function){
        let nextVal = updater(value);
        
        nextVal = Math.max(Math.min(nextVal, MAX_VALUE), MIN_VALUE);
        setValue(nextVal);
    }
    
    return (
        <>
            <h1>카운터 : {value}</h1>
            <p>max : {MAX_VALUE} / min : {MIN_VALUE}</p>
            {
                (value < MAX_VALUE) && 
                <button onClick={() => changeValue(a => a+1)}>
                    +1
                </button>
            }
            {   
                (value > MIN_VALUE) &&  
                <button onClick={() => changeValue(a => a-1)}>
                    -1
                </button>
            }
        </>
    );
}

/*
// 입력받은 값(a)에 1을 더해서 리턴하는 함수
const myUpdater = function(a) {
    return a + 1;
};
// function 키워드를 지우고 인수 뒤에 => 를 붙입니다.
const myUpdater2 = (a) => {
    return a + 1;
};
console.log(myUpdater(1));
console.log(myUpdater2(1));
//똑같다
*/

/*
    // 우리가 쓴 축약형
    () => changeValue(a => a + 1)

    // 이걸 전통적인 함수 형태로 길게 풀어쓰면
    function() {
        return changeValue(a => a + 1);
    }
*/

react에서 useState로 변수 처리
useState(초기값) => [값, 값설정함수]

button에서 onClick=changeValue() 하면
changeValue(
)가 바로 실행됨 즉, () (이름없는함수)로 이용
updater로 변수 유사 transaction 처리함

import { useState } from "react";
/* 왜 useState를 쓸까?

//리렌더링 함수가 있었으나, 후에 추적하기 어려워 삭제
//forceUpdate()
//또, 한 부분만 업데이트 하면 되기에 특수한 함수를 이용
//그냥 변수는 상수 처리로, 업데이트가 되지 않음.
let count: number = 0;

export default function App() {
    const [forceData, forceUpdate] = useState(0);

    function add() {
        count += 1;
        forceUpdate((forceData) => forceData + 1);
    }

    return (
        <>
            <p>{count}</p>
            <button onClick={
                add
            }>
                +1
            </button>
        </>
    )
}
*/

/* 기본 코드
export default function App() {
    const [count, setCount] = useState(0);
    // : [number, React.Dispatch<React.SetStateAction<number>>]

    return (
        <>
            <h1>카운터</h1>
            <p>{count}</p>
            <button onClick={() => setCount((val) => val + 1)}>
                +1
            </button>
            <button onClick={() => setCount((val) => val - 1)}>
                -1
            </button>
            <button onClick={() => setCount(0)}>
                리셋
            </button>
        </>
    )
}*/


// useState의 함수를 쓸 때, a => a+1 해야하는 이유
export default function App() {
    const [count, setCount] = useState(0);
    function add1() {
        setCount(a => a+1);
        setCount(a => a+1);
        setCount(a => a+1);
        // +3이 됨
    }

    function add2() {
        setCount(count + 1);
        setCount(count + 1);
        setCount(count + 1);
        // +1이 됨
    }
    return (
        <>
            <p>{count}</p>
            <button onClick={add1}>add1</button>
            <button onClick={add2}>add2</button>
            </>
    );
}

이게 그 예시

7

/*
구조 설계
MovieCardProps로 타입

App
ㄴMovieGrid
 ㄴMovieCard
   ㄴ Movie 관련 버튼 등
*/
import { useState } from "react";

interface Movie {
    id: number,
    title: string,
    releasedDate: Date,
    isBookmarked: boolean,
}

interface Arguments {
    movies: Movie[],
    onToggleBookmark: (id:number) => void
}

const initialMovies: Movie[] = [
    {id:1, title:"영화1", releasedDate:new Date("2026.09.22"), isBookmarked:false},
    {id:2, title:"영화2", releasedDate:new Date("2026.09.21"), isBookmarked:true},
    {id:3, title:"영화3", releasedDate:new Date("2026.09.20"), isBookmarked:false},
]

function MovieList({movies, onToggleBookmark}: Arguments) {
    return (
        <ul>
            {movies.map((movie) => 

                <li key={movie.id}>
                    <h3>{movie.title}</h3>
                    <p>{movie.releasedDate.toLocaleDateString()}</p>
                    <button
                        aria-pressed={movie.isBookmarked}
                        onClick={() => onToggleBookmark(movie.id)}
                    >
                        {movie.isBookmarked
                            ? "[O] 북마크 됨"
                            : "[ ] 북마크 하기"
                        }
                    </button>
                </li>

            )}
        </ul>
    );
}

function MovieGrid({movies, onToggleBookmark}: Arguments) {
    return (
        <>
            {movies.length === 0
                ? <p>영화가 없습니다.</p>
                : <MovieList movies={movies} onToggleBookmark={onToggleBookmark}/>
            }
        </>
    );
}

export default function App() {
    const [movies, setMovies] = useState(initialMovies);

    function onChangeBookmark(id: number)
    {
        setMovies((currentMovies) => 
            currentMovies.map((movie) =>
                (movie.id === id)
                    ? {...movie, isBookmarked: !movie.isBookmarked}
                    : movie
            )
        );
    }

    return (
        <>
            <h1>영화 목록</h1>
            <MovieGrid movies={movies} onToggleBookmark={onChangeBookmark} />
        </>
    )
}

파편화해서 관리 쉽게

...으로 unpacking후, 덮어씌우기로 isBookmarked이용
App 최상위에서
useState로, 변수 만들어주고
onChangeBookmark라는 변경 함수 만들어줌.
그 후, MoveGrid에 이거 전달
그 밑에 또 전달
또 전달

import { useState } from "react";

interface Movie {
    id: number,
    title: string,
    releasedDate: Date,
    isBookmarked: boolean,
}

const initialMovies: Movie[] = [
    {
        id: 1,
        title: "오디세이",
        releasedDate: new Date("2026.08.05"),
        isBookmarked: true,
    },
    {
        id: 2,
        title: "토이 스토리 5",
        releasedDate: new Date("2026.06.17"),
        isBookmarked: false,
    },
];

export default function App() {
    const [movies, setMovies] = useState(initialMovies);

    function handleToggleBookmark(movieID: number) {
        
        function getUpdatedMovies(currentMovies: Movie[])
        {
            currentMovies = currentMovies.map((movie) =>
                movie.id === movieID
                ? { ...movie, isBookmarked: !movie.isBookmarked} //덮어씌우기 !로 토글
                : movie,
            )
            return currentMovies;
        }

        setMovies(getUpdatedMovies);
    }

    function deleteMovie(movieID: number) {
        setMovies((currentMovies) => 
            currentMovies.filter((movie) => 
                movie.id !== movieID
            ) //조건 맞는 값들만 리턴
        )
    }

    function addMovie() {
        setMovies((currentMovies) =>
            [...currentMovies, 
                {
                    id : 99,
                    title : "ㅇ",
                    releasedDate: new Date("2026.09.22"),
                    isBookmarked: false,
                }
            ]
        )
    }

    return (
        <>
            <h1>영화목록</h1>
            <ul>
                {movies.map((movie) => (
                    <li key={movie.id}>
                        <h3>{movie.title}</h3>
                        <p>{movie.releasedDate.toLocaleDateString()}</p>
                        <button 
                            aria-pressed={movie.isBookmarked}
                            onClick={() => handleToggleBookmark(movie.id)}
                        >
                            {movie.isBookmarked
                                ? "[O] 북마크 됨"
                                : "[ ] 북마크하기"
                            }
                        </button>
                        <button
                            onClick={() => deleteMovie(movie.id)}
                        >
                            영화 제거하기
                        </button>
                    </li>
                ))}
            </ul>
            <button
                onClick={addMovie}
            >
                영화 추가하기
            </button>
        </>
    );

    /*
    setMovies(a => a) 처럼 아예 새로운 값으로 바꾸는 듯
    function handleToggleBookmark(movieID : number) {
        setMovies((currentMovies) => 
            currentMovies.map((movie) =>
                movie.id === movieID
                ? { ...movie, isBookmarked: !movie.isBookmarked} //덮어씌우기 !로 토글
                : movie,
            )
        );
    }*/
}

8

/*
코드 작성 순서를 주석으로 표시할게용
*/

//1
import { createContext, useContext, useState } from "react";

//2
type StudyMode = "focus" | "break";
//3
const initialStudyMode: StudyMode = "focus";
//4
const StudyModeContext = createContext<StudyMode>(initialStudyMode);

//8
function ModeStatus() {
    const mode = useContext(StudyModeContext);

    return (
        <h3>
            {mode === "focus" ? "집중중..." : "휴식중!!!"}
        </h3>
    )
}

//5
export default function App() {
    //6
    const [mode, setMode] = useState<StudyMode>(initialStudyMode);

    //10
    function toggleMode() {
        setMode((now) =>
            (now === "focus") ? "break" : "focus"
        );
    }

    return (
        //7
        <StudyModeContext.Provider value={mode}> 
            <h1>학습모드</h1>
            <ModeStatus></ModeStatus>
            <button onClick={toggleMode}>
                변경하기
            </button>
            {/* 9 */}
        </StudyModeContext.Provider>
    )
}

이때부터 좀 헷갈려서 코드 작성 순서 추가함
Context는 괄호 안의 변수 느낌.
로 그 안의 scope에 있는 친구들
그 변수들 쓸 수 있게 함.

이게 한 파일이어서 변수 값만 받았지,
원래는 변경 함수 등등 다 받는 게 좋음.
#7 에서는 props를 한땀한땀 자식으로 전달했다면,
Context는 useContext로 바로 이용 가능하게.

그래서 순서 정리하면

  1. Context 만들기
    변수, 변경함수, 그 외 변수 등 type으로 정의해서 만들기.
    어차피 그 Context 내부의 값은
    ~~.Provider에서 value={}로 지정하니까 기본은 공백함수 만들어도 ㄱㅊ ()=>{}

그니까 class 짜는 느낌인거임
instance는 <~.Provider></~.Provider> 로 만들고
initial value도 이때 value={}로 정의하니까 ㄱㅊ
그 안에 있는 친구들이 instance를 useContext로 이용 ㄱㄴ한거

  1. State로 변수 만들기 & 조작함수 만들기
    보통 상위 Fragment(Function으로 정의함) 안에서 만드는데
    그 Fragment 안에서 useState로 변수 처리할거임
    그러면 그 scope 안에서는 변수가 정의되어있으니까
    변수 처리해도 ㄱㅊ겠죠잉 그래서 변수 조작하는 function 만듦
    updater가 필요할 땐 그거 쓰면 굿. 유연하게 대처가 가능

  2. Provider
    이제까지 class 만들었으니까 instance 생성할 느낌
    먼저 ~.Provider로 <~.Provider>자식들</~.Provider>로 함
    자식들은 Provider에서 준 Context 이용 가능.
    Provider에서 기본 값 설정은 value={값,값,값 ...}으로 함
    값에 key:value아니라 value꼴로 넣는다면 순서 중요하니 유의

  3. useContext로 값 써먹기
    그 Provider의 자식들이 useContext(그 Context)로 값이나 변수들 가져올 수 있음.
    보통 const {변수들 중 필요한 것들만} = useContext(그 Context);
    꼴로 가져오고 알아서 잘 쓰면 됨

미션

App

ㄴHeader

ㄴPagination

ㄴPageProvider

ㄴMovieProvider 이 Provider를 병렬로 처리하기엔 한 Provider가 여러 역할할 듯

ㄴMovieGrid

ㄴMovieCard

ㄴPageSelector
    //App.tsx
    
    import Header from "./header";
    import Pagination from "./pagination";
    
    export default function App() {
        return (
            <main>
                <Header></Header>
                <Pagination></Pagination>
            </main>
        );
    }
    ```
    
    ```tsx
    //header.tsx
    
    export default function Header() {
        return (
            <h3>헤더입니당</h3>
        )
    }
    ```
    
    ```tsx
    //pagination.tsx
    
    import MovieGrid from "./movie-grid";
    import { MovieProvider } from "./movie-context";
    import { PageProvider } from "./page-context";
    import { PageSelector } from "./page-selector";
    
    export default function Pagination() {
        return (
            <PageProvider>
                <MovieProvider>
                    <h2>영화 목록</h2>
                    <MovieGrid></MovieGrid>
                    <PageSelector></PageSelector>
                </MovieProvider>
            </PageProvider>
        );
    }
    ```
    
    ```tsx
    //page-context.tsx
    
    import { createContext, useState } from "react";
    
    const initialPage: number = 1;
    const possiblePages: number[] = [1,2,3,4,5];
    
    type PageContextType = {
        page: number,
        possiblePages: number[],
        changePage: (page:number) => void,
    };
    export const PageContext = createContext<PageContextType>({
        page: initialPage,
        possiblePages: possiblePages,
        changePage: () => {},
    });
    
    export function PageProvider({ children }) {
        const [page, setPage] = useState<number>(initialPage);
    
        const changePage = (page: number) => {
            setPage(() => page);
        }
    
        return (
            <PageContext.Provider value={{page, possiblePages, changePage}}>
                {children}
            </PageContext.Provider>
        );
    }
    ```
    
    ```tsx
    //movie-context.tsx
    
    import { createContext, useState } from "react";
    import { type Movie } from "./types/movie";
    import { movies } from "./data/movies";
    
    const initialMovie: Movie[] = movies;
    
    type MovieContextType = {
        movies: Movie[],
        toggleBookmark: (id:number) => void,
    };
    export const MovieContext = createContext<MovieContextType>({
        movies : initialMovie,
        toggleBookmark: () => {},
    });
    
    export function MovieProvider({ children }) {
        const [movies, setMovies] = useState<Movie[]>(initialMovie);
    
        const toggleBookmark = (id:number) => {
            setMovies(movies => movies.map((movie) => 
                movie.id === id 
                    ? {...movie, isBookmarked: !movie.isBookmarked} 
                    : movie
            ))
        }
    
        return (
            <MovieContext.Provider value={{movies, toggleBookmark}}>
                {children}
            </MovieContext.Provider>
        );
    }
    ```
    
    ```tsx
    //movie-grid.tsx
    
    import { useContext } from "react";
    import { MovieContext } from "./movie-context";
    import MovieCard from "./movie-card";
    import { PageContext } from "./page-context";
    import "./movie-grid.css";
    
    export default function MovieGrid() {
        const {movies} = useContext(MovieContext);
        const {page} = useContext(PageContext);
    
        const START = 0;
        const COUNT = 3;
    
        const targetMovies = movies.slice(START+(page-1)*COUNT, START+COUNT*page);
    
        return (
            <div className="movie-grid">
                {targetMovies.length === 0
                    ? <p>영화가 없습니다</p>
                    : targetMovies.map((movie) => (
                        <MovieCard key={movie.id} movie={movie}/>
                    ))
                }
            </div>
        );
    }
    ```
    
    ```tsx
    //movie-card.tsx
    
    import { type Movie } from "./types/movie";
    import { useContext } from "react";
    import { MovieContext } from "./movie-context";
    import "./movie-card.css";
    
    type MovieCardProps = {
        movie : Movie
    }
    
    export default function MovieCard({movie} : MovieCardProps) {
        const {toggleBookmark} = useContext(MovieContext);
    
        return (
            <div className="movie-card">
                <img className="movie-card__poster" src={movie.posterPath}></img>
                <h3>{movie.title}</h3>
                <p>{movie.genres}</p>
                <p>{movie.releaseDate}</p>
                <button onClick={() => toggleBookmark(movie.id)} aria-pressed={movie.isBookmarked}>
                    {movie.isBookmarked ? "북마크됨" : "북마크하기"}
                </button>
            </div>
        )    
    }
    ```
    
    ```tsx
    //page-selector.tsx
    
    import { PageContext } from "./page-context";
    import {useContext} from "react";
    
    export function PageSelector() {
        const {page, possiblePages, changePage} = useContext(PageContext);
        
        return (<div>
            {possiblePages.map((pageNum) => (
                <button onClick={() => changePage(pageNum)}>
                    {page === pageNum ? `[ ${pageNum} ]` : pageNum}
                </button>
            ))}
        </div>);
    }
    ```
    
    
    
    - React 컴포넌트와 JSX
    - JSX는 HTML과 어떤 점이 다르며 React 컴포넌트 안에서 어떤 역할을 하나요?
        
        JavaScript의 확장으로, {}안에 표현식으로 쉽게 이용할 수 있고, 가독성이 좋다.
        
    - 하나의 화면을 여러 컴포넌트로 나누면 어떤 장점이 있으며, 분리 기준은 어떻게 정할 수 있을까요?
        
        자주 쓰는 것, 너무 많은 일을 하지 않게 등. 함수와 비슷하게 처리하자
        
    - 조건부 렌더링과 목록 렌더링은 데이터에 따라 보여 줄 컴포넌트를 어떻게 결정하나요?
        
        조건이나 값에 따라 렌더링 제어. 목록은 map으로 순환해서 렌더링
        
- props와 단방향 데이터 흐름
    - 부모와 자식 컴포넌트 사이에서 props는 어떤 역할을 하나요?
        
        내려가는 데이터
        
    - 데이터가 부모에서 자식으로만 흐르면 화면의 변화를 추적하는 데 어떤 도움이 되나요?
        
        역추적이 한 방향이어서 좋음
        
    - props에 TypeScript 타입을 붙이면 컴포넌트를 잘못 사용하는 실수를 어떻게 찾을 수 있나요?
        
        오타방지
        
- 상태와 리렌더링
    - 일반 변수와 state(상태)는 값이 바뀐 뒤 화면을 다시 보여 주는 방식이 어떻게 다른가요?
        
        변수는 바뀌어도 리렌더 ㄴㄴ state는 감지해서 리렌더
        
    - React에서 원본 상태를 직접 수정하지 않고 새로운 값으로 업데이트해야 하는 이유는 무엇일까요?
        
        리액트는 이전 상태와 참조 값 비교로 빠르게 판단함. 그래서 원본 직접 수정하면 주소고정 ⇒ 뭐가 바뀐거고 ;; 라고 함
        
    - 이전 상태로 다음 상태를 계산할 때 업데이터 함수를 사용하는 이유는 무엇일까요?
        
        a ⇒ a+1 같은 거 쓰면 유연하게 이용 가능. add, subtract, multiply 등으로 함수 나누거나 설정 안해도 a ⇒ a에 관한 연산 으로 쉽게 가능
        
- 상태 공유와 Context
    - 여러 컴포넌트가 같은 상태를 사용해야 할 때 상태를 어느 컴포넌트에 두는 것이 좋을까요?
        
        위에 있는 게 좋음. 근데 너무 위면 굳이고, 가장 가까운 공통 조상 ㄱㄱ (상태 끌어올리기)
        
    - props 전달, 상태 끌어올리기와 Context는 각각 어떤 상황에 알맞을까요?
        
        prop은 부모⇒자식 단순히 한 칸 전달할 때 굿
        
        상태 끌어올리기는 형제들끼리 데이터 공유할 때 공통 부모로 이동
        
        Context는 부모 자식 너무 깊어서 힘들 때나 전역 공유
        
    - 모든 값을 Context로 전달하면 어떤 문제가 생길 수 있을까요?
        
        Context 변경하면 그 하위 트리가 다 리렌더링됨.
        
        그니까 하나만 바뀌어도 그 밑이 바뀔 수 있기에 성능 저하 가능.

0개의 댓글