본문 바로가기
카테고리 없음

리엑트 기본

by chu_dw 2026. 4. 26.

프로젝트에서 프론트를 만들어야 할 일이 생겼다...!

하지만 진짜 아무것도 모르는 상황.. 정말 간단한 crud 받는 것만 next 써서 해본 게 다였는데

이번 프로젝트는 좀 많은 걸 요구할 거 같다.

 

지도를 렌더링해서 실시간 위치를 추적하는 기능까지 필요하다.

대충 찾아보니 상태관리가 잘 되어야 할 것 같은데

관련하여 전혀 모르겠어서 기본부터 공부하며 정리해 보려고 한다.

 

아래부터 하나하나 타고 올라올 시간 까지는 없기 때문에

내가 필요한 정보에서 탑다운으로 내려가면서 알아볼 예정이다.

 

실시간 기능을 쓰기 위해선 상태관리가 필수라고 한다.

그럼 리엑트에서 상태관리에 대해 알아보겠다.

 

리엑트 상태관리

리엑트에서 상태란 컴포넌트 속 ui를 결정하는 데이터를 의미한다.

사용자와의 상호작용에 따라 이 상태는 계속 업데이트된다.

변화하는 상태를 앱의 다양한 부분이 일관되게 공유하여 올바르게 반응하게 하는 것이

리엑트의 상태관리이다.

 

상태관리가 잘 안 될 경우

사용자가 검색 필터에서 ‘저녁’을 선택했지만,
메인 화면의 지도는 여전히 이전 상태(예: 전체 데이터)를 표시하는 문제가 발생한다.

 

리엑트가 상태관리 하는 법

리엑트는 기본적으로 컴포넌트의 state와 props를 사용한다.

그리고 나는 이 프로젝트에선 상태관리를 해주는 라이브러리인 Zustand를 사용할 예정이다.

 

컴포넌트, state, props 란?

 

리엑트 컴포넌트

ui를 구성하는 독립적인 단위이다. 

함수 형태로 작성되어, 다른 컴포넌트와 조합해서 전체 화면 구성 한다.

 

state

컴포넌트 내부에서 관리되는 변경 가능한 데이터

 

props (프로퍼터)

부모 컴포넌트에서 자식 컴포넌트로 전달되는 읽기 전용 데이터

 

아직 감이 잘 안 와서 예시 하나로 정리해 보겠다

function Parent() {
  const [name, setName] = useState("철수");

  return <Child name={name} />;
}

function Child({ name }) {
  return <div>{name}</div>;
}
  • parent라는 컴포넌트를 생성한다.
  • useState를 사용해 name이라는 상태와, 해당 상태를 변경하기 위한 setName 함수를 정의한다
  • name 상태를 "철수"로 초기값 설정한다.
  • 초기화된 상태 값을 props로 Child 컴포넌트에 전달한다.
  • Child 컴포넌트에서 name 값 div로 출력한다.

parent가 상위 컴포넌트가 된 이유 = Parent가 Child를 렌더링 했기 때문

 

컴포넌트 구조가 복잡해지면?

import { useState } from "react";
import FilterBar from "./components/FilterBar";
import Map from "./components/Map";
import Alert from "./components/Alert";

function App() {
  const [filter, setFilter] = useState("ALL");

  return (
    <>
      <FilterBar setFilter={setFilter} />
      <Map filter={filter} />
      <Alert filter={filter} />
    </>
  );
}

export default App;

기본 APP(전체 UI 감싸는 최상단 컴포넌트) 코드이다.

여기서 filter라는 상태를 만들고 있다, 변경 함수는 setFilter이고 초기화는 ALL 로 해준다.

그리고 FilterBar에는 함수를 전달, Map과 Alert에는 상태를 props(프로퍼터)로 전달한다.

 

import Marker from "./Marker";

function Map({ filter }) {
  return (
    <div>
      <h3>지도</h3>
      <Marker filter={filter} />
    </div>
  );
}

export default Map;

다음은 지도를 표현해 주는 Map 컴포넌트이다.

여기서 maker 컴포넌트를 호출해 사용한다. (지도 위에 마커 띄우기)

즉 map은 filter상태가 필요 없더라도, 안에 있는 marker가 필요해서 fileter를 app으로부터 전달만 한다.

 

여기서 더 복잡해진다고 가정해 보자

App -> Map -> Roadlayer -> Segment -> marker 이런 식으로 컴포넌트가 구성되어 있고

marker에선 상태 변경도 해야 한다.

marker에서 APP의 상태를 변경하기 위해선 거쳐오는 모든 컴포넌트에

props(프로퍼터)로 setFilter={setFilter} 사용해서 함수를 전달해야 한다.

 

이렇게 다 만든 상태에서, 갑자기 marker를 map 아래로 옮기고 싶어 진다면?

ROADLAYER, SEGMENT, marker안에 있는 props 경로를 모두 수정해줘야 한다.

 

 

Zustand

위와 같은 문제는 전역상태관리 라이브러리인 Zustand(주스탠드)를 사용하여 해결할 수 있다.

(redux보다 간단한 편이라 들어서 Zustand로 결정)

Zustand는 상태를 컴포넌트 외부 저장소에 저장하여 props(프로퍼터) 사용 없이 상태를 사용한다. 

 

[코드 보기 전 찾아본 자바스크립트 문법]

- 익명함수

자바스크립트에선 이름 없는 익명 함수가 있다.

function(a, b) {
  return a + b;
}

 

- 화살표 함수

화살표 함수를 사용해 함수를 간결하게 나타낸다.

위 익명 함수를 화살표 함수로 나타낸 것이다.

(a,b) => a+b

 

 

Zustand 사용

import { create } from "zustand";

const useFilterStore = create((set) => ({
  filter: "ALL",

  setFilter: (newFilter) =>
    set({ filter: newFilter }),
}));
  • "create((set) => ..."을 호출해 useFilterStore라는 이름의 저장소를 만든다.
  • 이때 매개변수 set은 Zustand가 제공하는 상태를 변경함수이다.
  • filter라는 상태를 만드로 "ALL"로 초기값으로 설정해 준다.
  • setFilter라는 함수를 정의, newFilter를 매개변수로 받는다.
  • 이 함수는 filter상태를 매개변수로 받은 newFilter로 변경한다.

Zustand는 현재상태 조회하는 get함수도 제공지만 set에 현재 state 콜백 받아 사용하는 경우가 더 많다고 한다.

 

모든 상태를 외부 저장소에 저장하진 않고

여러 컴포넌트에서 사용될 상태만 저장한다.

 

 

useEffect

리엑트는 컴포넌트 렌더링 기준으로 동작한다.

렌더링이 된 후 useEffect가 동작해 특정작업을 실행할 수 있다.

import { useEffect } from "react";

function App() {

  useEffect(() => {
    console.log("처음 실행");
  }, []);

  return <h1>Hello</h1>;
}

useEffect뒤에 빈배열은 첫 렌더링에만 useEffect가 실행되도록 해준다.
(배열 없으면 렌더링 될 때마다 실행)

해당 배열에 상태를 넣어주면 해당 상태가 바뀔 때 useEffect가 실행된다.

 

useEffect cleanup

useEffect 내부에서 return 함수를 정의하면 cleanup 함수가 된다.

useEffect(() => {

  const timer = setInterval(() => {
    console.log("실행");
  }, 1000);

  return () => {
    clearInterval(timer);
  };

}, []);
  • 컴포넌트가 제거될 때 실행
  • 이벤트리스너, 타이머, 외부라이브러리 등을 정리해주어야 한다.
  • 사라진 컴포넌트 계속 동작, 이벤트 중복을 방지한다.

useEffect 무한루프

useEffect(() => {
  setCount(count + 1);
}, [count]);

count가 변경되면 동작하는 useEffect인데 useEffect안에서 count를 변경하여 무한루프에 걸려 버린다.