
React는 단방향으로 바인딩하는 라이브러리
부모 ➡️ 자식방향으로만state를props로 전달함.- 자식의
props를 부모에게 전달하는 방법은 존재하지 않는다.
자식에게 부모의
state를 modify 할 수 있는setState함수를props로 넘겨준다.
state management tool(recoil, Jotai 등)을 활용한다.
Parent.js
import React from "react";
import MyComponent from "./MyComponent";
function App() {
return(
<MyComponent propValue="헬로 리액트!">Bye 리액트!</MyComponent>
);
}
export default App;
Children.js
import React from "react";
function MyComponent(props) {
return(
<div>
{props.propValue}, {props.children}
</div>
);
}
export default MyComponent;

propValue를 자식 component의 propValue로 내려보내 자식 component에서 활용할 수 있음.Props drilling )
**Props Drilling**→ props를 하위 컴포넌트로 전달하는 과정에서 몇 개의 컴포넌트를 뚫고 들어가는 형태를 의미.props를 전달하는 컴포넌트가 적을 땐 문제가 없으나, 많은 컴포넌트들을 뚫고 state를 전달해야 한다면 그 props를 추적하기 어려워진다.
**Redux**,**Recoil**,**Jotai**등의 전역 상태 관리 라이브러리를 사용하여 이와 같은 props drilling을 방지할 수 있다.
그래서 얘 왜 써 ?
→ 대규모 애플리케이션에 강력한 상태 관리 솔루션을 제공함
→ useState는 로컬 상태 관리에서 주로 사용하는 반면, Redux는 전역 상태 관리에서 주로 사용
즉,useState는 컴포넌트 범위의 상태 관리를 위한 것이고,Redux는 애플리케이션 전체 범위의 상태 관리를 위한 것
하지만 Redux를 쓰는 것이 항상 좋지만은 않다. 초기 설정과 사용 방법이 어렵기도 함.
프로젝트의 규모나 상태 관리의 필요성에 따라 적절한 도구를 선택하는 것이 중요
// store.ts
import { configureStore } from '@reduxjs/toolkit';
// 상태 타입 정의
interface CounterState {
value: number;
}
// 초기값 설정
const initialState: CounterState = {
value: 0,
};
// Reducer 함수 정의. 액션 타입에 따라 상태를 변화시킴.
function counterReducer(state = initialState, action: { type: string }): CounterState {
switch (action.type) {
case 'counter/incremented':
return { ...state, value: state.value + 1 };
case 'counter/decremented':
return { ...state, value: state.value - 1 };
default:
return state;
}
}
// 스토어 생성.
const store = configureStore({
reducer: {
counter: counterReducer,
},
});
export default store;
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
// actions.ts
export const increment = () => ({
type: 'counter/incremented',
});
export const decrement = () => ({
type: 'counter/decremented',
});
// Counter.tsx
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { RootState, AppDispatch } from './store';
import { increment, decrement } from './actions';
const Counter: React.FC = () => {
// useSelector를 사용해 스토어의 상태를 선택.
const count = useSelector((state: RootState) => state.counter.value);
// useDispatch를 사용해 Action을 Dispatch하는 함수를 가져올 수 있음.
const dispatch: AppDispatch = useDispatch();
return (
<div>
<div>Value: {count}</div>
<button onClick={() => dispatch(increment())}>Increment</button>
<button onClick={() => dispatch(decrement())}>Decrement</button>
</div>
);
};
export default Counter;
// App.tsx
import React from 'react';
import { Provider } from 'react-redux';
import store from './store';
import Counter from './Counter';
const App: React.FC = () => {
return (
<Provider store={store}>
<Counter />
</Provider>
);
};
export default App;
**Counter** 컴포넌트에서 버튼을 클릭할 때마다, Redux 스토어의 상태가 업데이트된다.**Counter** 컴포넌트에 반영
**atoms**과**selectors**로 관리
- Atoms: 애플리케이션의 상태의 일부를 나타내며, 어떤 컴포넌트에서든 상태를 읽거나 쓸 수 있음.
- Selectors: 파생된 상태를 나타내며, atom의 상태에 의존하고, atom의 상태가 바뀔 때마다 자동으로 갱신.
React의 컨텍스트에 더 가깝게 설계되었으며, 각 Atom을 구독하는 컴포넌트만 리렌더링되어 성능 이점을 제공
Recoil은 상태를 전역적으로 관리하면서도 React의 Hooks 패턴과 잘 어울려, 친숙한 패턴으로 상태 관리를 할 수 있게 해줌.
// state.ts
import { atom } from 'recoil';
export const counterState = atom({
key: 'counterState', // 고유한 ID(다른 atoms/selectors와 구분을 위함)
default: 0, // 기본값
});Recoil의 상태를 정의
// Counter.tsx
import React from 'react';
import { useRecoilState } from 'recoil';
import { counterState } from './state';
const Counter: React.FC = () => {
const [count, setCount] = useRecoilState(counterState);
return (
<div>
<div>Count: {count}</div>
<button onClick={() => setCount(count + 1)}>Increment</button>
<button onClick={() => setCount(count - 1)}>Decrement</button>
</div>
);
};
export default Counter;
이 상태를 사용하는 컴포넌트를 생성
// App.tsx
import React from 'react';
import { RecoilRoot } from 'recoil';
import Counter from './Counter';
const App: React.FC = () => {
return (
<RecoilRoot>
<Counter />
</RecoilRoot>
);
};
export default App;
RecoilRoot를 사용하여 Recoil 상태 트리를 제공
전역 상태를
**atoms을 사용해 관리하는데, 이들은 Recoil에서처럼 상태의 작은 단위로 작동
목표는 최소한의 API로 상태를 쉽게 관리하는 것**
작은 규모의 프로젝트를 진행할 시 유리
- Typescript 기반이고 업데이트가 주기적이다 *
- 예시
```tsx
// state.ts
import { atom } from 'jotai';
export const counterAtom = atom(0); // 초기값이 0인 atom
```
- **우선적으로 atom을 정의**
// Counter.tsx
import React from 'react';
import { useAtom } from 'jotai';
import { counterAtom } from './state';
const Counter: React.FC = () => {
const [count, setCount] = useAtom(counterAtom);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(c => c + 1)}>Increment</button>
<button onClick={() => setCount(c => c - 1)}>Decrement</button>
</div>
);
};
export default Counter;
**useAtom** 훅을 사용하여 atom의 값을 읽고 설정**setCount** 함수를 호출하여 상태를 업데이트하면, 해당 atom을 사용하는 모든 컴포넌트가 자동으로 업데이트[지원 : 동국대학교 SW교육원]