사용자 인터페이스를 나타내는 모든 데이터로, 상태는 시간이 지남에 따라 변할 수 있다.
리액트는 상태와 함께 렌더링할 컴포넌트를 처리한다.
🌟 상태관리?!
변화하는 데이터, 즉 상태에 맞춰 적절한 UI/UX를 설계하고 구현하는 모든 일
지역상태란?
전역상태란?
✔️ 다른 컴포넌트에게 상태를 전달하려면?
-> 우리는 props를 사용해서 전달 (부모가 자식에게 값을 전달하는 느낌!)
상태관리에 대해서 정리하다보니 헷갈리는 3가지 ..
정리하고 보면 생각보다 간단하다!
// 1. state
function A() {
const [count, setCount] = useState(0);
return <div>{count}</div>;
}
// 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 발생!!
// 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는 서로 관계 없어도 같은 상태 사용 중!
전역 상태 구현
- 리액트 내장 툴 (Context API)
- 상태 관리 라이브러리 (ex. Recoil, Redux 등등)
-> 둘 다 여러 컴포넌트에서 같은 상태를 공유하기 위함이다!
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은 React 상태 관리를 위한 라이브러리로, 컴포넌트 간 전역 상태를 간단하게 공유할 수 있게 해준다.
Recoil의 장점
1. 전역 상태의 설정/정의가 비교적 쉽다
2. Recoil이 지원하는 Hook을 이용해 데이터를 get/set하기 때문에 React 문법과 매우 유사하다
🌟 상태를 전역으로 등록해두고 필요한 곳에서 바로 꺼내 쓰면서 !! 위에서 언급한 props drilling 문제를 해결할 수 있다 🌟
| 개념 | 설명 |
|---|---|
RecoilRoot | 앱 전체에 Recoil 기능을 적용하려면 최상단에 감싸야 함 |
atom | 전역 상태의 단위 (state 하나) |
selector | atom 기반으로 계산된 상태(->atom 파생 형태!!) |
useRecoilState | atom을 읽고 쓰는 Hook (useState처럼 동작) |
useRecoilValue | 읽기 전용으로 atom이나 selector 사용 |
useSetRecoilState | 쓰기 전용으로 사용하고 싶을 때 |
npm i recoil
import { RecoilRoot } from 'recoil';
function App() {
return (
<RecoilRoot>
<MyApp />
</RecoilRoot>
);
}
// state.js
import { atom } from 'recoil';
export const countState = atom({
key: 'countState', // 고유 ID
default: 0, // 초기값
});
// 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>
</>
);
}