[React] 상태관리와 Recoil

밍도이·2025년 7월 1일

React

목록 보기
1/1

상태(State)란?

사용자 인터페이스를 나타내는 모든 데이터로, 상태는 시간이 지남에 따라 변할 수 있다.
리액트는 상태와 함께 렌더링할 컴포넌트를 처리한다.

🌟 상태관리?!
변화하는 데이터, 즉 상태에 맞춰 적절한 UI/UX를 설계하고 구현하는 모든 일

상태관리가 왜 필요할까?

  • 상태가 바뀌었을 때, 페이지 전체가 아닌 필요한 컴포넌트만 렌더링 할 수 있다.
  • 네트워크 통신 횟수를 획기적으로 줄일 수 있다
  • 의도하지 않은 UI/UX를 보여주지 않을 수 있다.

지역상태 vs 전역상태

지역상태란?

  • 특정 컴포넌트 내부에서만 관리되는 상태
  • 다른 컴포넌트들과 상태 공유 X

전역상태란?

  • 프로젝트 전체에서 접근할 수 있는 상태
  • 여러 컴포넌트들과 공유됨

✔️ 다른 컴포넌트에게 상태를 전달하려면?
-> 우리는 props를 사용해서 전달 (부모가 자식에게 값을 전달하는 느낌!)

state vs props vs 전역상태(ex.Recoil)

상태관리에 대해서 정리하다보니 헷갈리는 3가지 ..
정리하고 보면 생각보다 간단하다!

  1. state란?
  • 내 컴포넌트 안에서만 쓰는 지역 상태
  • useState()로 선언하고 setState()로 업데이트
// 1. state

function A() {
  const [count, setCount] = useState(0);

  return <div>{count}</div>;
}
  1. props
  • state를 자식 컴포넌트에게 전달하는 통로
  • 직접 값을 바꾸지 못하고 받기만 !! 함
// 2. props
function A() {
  const [count, setCount] = useState(0);

  return <B count={count} />;
}

function B({ count }) {
  return <C count={count} />;
}

function C({ count }) {
  return <div>{count}</div>;
}
// → B, C는 직접 만든 게 아니라 받은 것! (props)

추가적으로 상위 컴포넌트에서 목표 컴포넌트로 props를 전달하기 위해, 수많은 중간 컴포넌트를 오직 데이터 전달 용도로만 사용하면 Props Drilling 발생!!

  1. 전역상태(ex.Recoil)
  • 어떤 컴포넌트든 중간 거치지 않고 바로 상태를 가져와서 쓸 수 있게 함.
  • 복잡한 구조에서도 상태를 쉽게 공유 ✨
// 3. Recoil
// 어떤 컴포넌트든 그냥 useRecoilState(atom) 하면 바로 쓸 수 있다!!

function A() {
  const [count, setCount] = useRecoilState(myState);
  return <div>{count}</div>;
}

function X() {
  const [count, setCount] = useRecoilState(myState);
  return <button onClick={() => setCount(count + 1)}>+</button>;
}
// A랑 X는 서로 관계 없어도 같은 상태 사용 중!

전역 상태 구현

  1. 리액트 내장 툴 (Context API)
  2. 상태 관리 라이브러리 (ex. Recoil, Redux 등등)
    -> 둘 다 여러 컴포넌트에서 같은 상태를 공유하기 위함이다!

Context API

Context API는 리액트의 내장 API로, 앱에서 컴포넌트에게 props를 사용하지 않고 필요한 데이터(state)를 쉽게 공유할 수 있게 해준다.
즉 앱의 모든 컴포넌트에서 사용할 수 있는 데이터(state)를 전달할 때 유용하다.

주로 테마 데이터(다크 모드, 라이트 모드), 사용자 데이터(현재 인증된 사용자), 언어 혹은 지역 데이터 등등 자주 업데이트할 필요가 없는 데이터에 사용한다.

// ThemeContext.js
import { createContext, useState, useContext } from 'react';

const ThemeContext = createContext();

export const ThemeProvider = ({ children }) => {
  const [isDark, setIsDark] = useState(false);
  return (
    <ThemeContext.Provider value={{ isDark, setIsDark }}>
      {children}
    </ThemeContext.Provider>
  );
};

export const useTheme = () => useContext(ThemeContext);
// App.js
<ThemeProvider>
  <Page />
</ThemeProvider>

// Page.js
const { isDark, setIsDark } = useTheme();

⚠️ context 주의사항 ⚠️
Provider를 사용할 경우 context의 value가 갱신됨
-> 모든 context의 Consumer들이 컴포넌트를 리렌더링

즉 context를 사용하지 않음에도, 이를 사용하는 부모 컴포넌트가 리렌더링됨에 따라 자식 컴포넌트가 리렌더링 되는 불필요한 렌더링 발생 !!!

Recoil이란?

Recoil은 React 상태 관리를 위한 라이브러리로, 컴포넌트 간 전역 상태를 간단하게 공유할 수 있게 해준다.

Recoil의 장점
1. 전역 상태의 설정/정의가 비교적 쉽다
2. Recoil이 지원하는 Hook을 이용해 데이터를 get/set하기 때문에 React 문법과 매우 유사하다

🌟 상태를 전역으로 등록해두고 필요한 곳에서 바로 꺼내 쓰면서 !! 위에서 언급한 props drilling 문제를 해결할 수 있다 🌟

Recoil 구조

개념설명
RecoilRoot앱 전체에 Recoil 기능을 적용하려면 최상단에 감싸야 함
atom전역 상태의 단위 (state 하나)
selectoratom 기반으로 계산된 상태(->atom 파생 형태!!)
useRecoilStateatom을 읽고 쓰는 Hook (useState처럼 동작)
useRecoilValue읽기 전용으로 atom이나 selector 사용
useSetRecoilState쓰기 전용으로 사용하고 싶을 때

Recoil 사용법

  1. Recoil 라이브러리 설치
npm i recoil
  1. 루트 컴포넌트를 RecoilRoot로 감싸기
import { RecoilRoot } from 'recoil';

function App() {
  return (
    <RecoilRoot>
      <MyApp />
    </RecoilRoot>
  );
}
  1. atom 만들기(전역 상태 만들기)
// state.js
import { atom } from 'recoil';

export const countState = atom({
  key: 'countState',   // 고유 ID
  default: 0,          // 초기값
});
  1. 컴포넌트에서 상태 사용하기
// Counter.js
import { useRecoilState } from 'recoil';
import { countState } from './state';

function Counter() {
  const [count, setCount] = useRecoilState(countState);

  return (
    <>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>+1</button>
    </>
  );
}
profile
거친세상에뛰어든건나니까암오케.

0개의 댓글