안녕하십니까
야생에서 등장한 하프 입니다 😊
리액트에서 전역적으로 상태관리가 주어진다고 한다면, 아무래도 필요한것이.. 전역 상태관리 일거시옵니다~
간단하고 핵심만 짚어서 해드릴테니 잘 따라오시면 되겠습니다 👌
Redux, Recoil 이란?
전역 상태관리를 해주는 라이브러리로 많이들 알고 계실 겁니다 ~
주로 Redux는 대부분 알고 계신거 같더라구요.
이것을 왜? 사용하는가 한다면 바로 props 때문입니다.
props는 부모에서 자식에게 넘겨줄 수 있지만,
자식에서 부모로 props를 넘겨줄 수는 없습니다.
그래서 자식에게 useState 변수를 넘겨준다고 한다면, props는 너무나도 복잡해지게 됩니다.
즉, 유지보수가 힘들어지게 되겠지요.

그래서 우리는 이것을 `어딘가`에 변수를 저장해두고 내가 원할때마다 가져다 쓰자! 하는것이 전역상태관리 입니다.
1. Redux
Redux(리덕스)의 경우 익숙한 구조에 신뢰성이 높다고 볼 수 있습니다.
대신에! 하나를 변경하려고 해도 actions, reducer, store등 등 등.. 다 변경 해줘야 하는 번거러움 있지요.
하지만 번거로움에는 큰 이점도 따른 다는것!.. 명심해주세요.
2. Recoil
Recoil(리코일)의 경우는 리덕스보다 좀 더 간단하게 사용할 수 있는 라이브러리 라고 보면 됩니다.
리코일에도 atom, selet 등 다양한 기능들이 있으니.. 한 가지에 익숙해진다면, 러닝 커브가 살짝 일어날 수 있습니다.
그치만!!.. 편리한것에 있어서 매우 좋다고 할 수 있지요.
3. Redux? Recoil? 어떤걸 사용해야 할까
Redux와 Recoil의 상태관리 라이브러리를 선택하기 전에 있어서 프로젝트의 규모를 살펴봐야 할 것 같습니다.
주인장의 경우는 ..
프로젝트의 규모가 크고 디버깅이 많이 필요하다 싶으면 Redux 를
프로젝트의 규모가 작고 간단하게 진행을 하고 싶다 하면 Recoil 을 추천드립니다.
전 개인적으로 리코일을 선호하는 편 입니다.
이것저것 맞춰주기 귀찮아서 그냥.. 사용합니다 😅
서론이 길어졌네요 바로 사용법에 대해 알아보도록 합시다 ~
다른 글들을 보면 여기는 저렇게, 저기는 저렇게 방식이 전부 다르기도 해서, 헷갈리기도 합니다.
그래서 한번에 보기 쉽게 딱!!! 정리 해드리겠습니다.
물론 정리해놓고 나중에 제가 보기 위함 이지만요 😊
Redux 사용법
1. 라이브러리 설치
필요한 라이브러리는 다음과 같습니다.
redux 와 react-redux를 설치해주시면 됩니다.
npm i redux react-redux
2. 파일 구조
상태관리를 해주기 위해서 파일 구조를 다음과 같이 잡았습니다.
📁 src
└─ 📁 redux
└─ 📁 actions
└─ 📜 coffeeAction.js
└─ 📁 reducers
└─ 📜 coffeeReducer.js
└─ 📜 store.js
크게 Actions, Reducers, Store 3개로 분류가 됩니다.
아래의 코드들은 그대로 따라 붙여넣어도 됩니다.
3. 리덕스 설정
액션(Actions)
액션은 웹으로부터 온 데이터를 Store에 전송할 수 있도록 하는 Payload 입니다.
/src/redux/actions/coffeeAction.js
export const addCoffee = (coffeeData) => ({
type: "ADD",
payload: coffeeData
})
- type : 웹으로부터 전달받은 수행할 Type 입니다.
- payload : 웹으로부터 전달받은 데이터 입니다.
리듀서(Reducers)
액션(Action)에서 전달 받은 Type을 실행하는 구문 입니다.
Switch를 통해서 전달받은 Type에 따라 다르게 구문을 수행할 수 있습니다 !!..
/src/redex/reducers/coffeeReducer.js
const coffeeReducer = (state = [], action) => {
switch (action.type) {
case 'ADD':
state.push(
action.payload
)
return state;
default:
return state;
}
};
export default coffeeReducer;
스토어(store)
'스토어는 리듀서(Reducers)들을 관리해주는 것' 이라고 생각하시면 됩니다!
/src/redux/store.js
import { combineReducers, createStore } from 'redux';
import coffeeReducer from './reducers/coffeeReducer';
const rootReducer = combineReducers({
coffee: coffeeReducer
})
let store = createStore(rootReducer);
export default store;
이제 마지막으로 index.js만 수정해주면 됩니다.!!!
/src/index.js
import { Provider } from 'react-redux';
import store from "./redux/store";
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render( // Provider 추가..!
<Provider store={store}>
<App />
</Provider>
);
4. 데이터 불러오기
리덕스에서는 useSelector와 useDispatch가 있습니다!
useSelector의 경우는 조회할 때 사용을 하고
useDispatch의 경우는 업데이트할 때 사용을 합니다!
우선 app.js를 간단하게 꾸며보도록 할게요.
/src/app.js
import { useState } from 'react';
function App() {
let [coffee, setCoffee] = useState({
title: "",
price: 0
})
const onClick = () => {
}
return (
<div className="App">
커피 이름 : <input value={coffee.title} onChange={(e) => {
setCoffee({
...coffee,
title: e.target.value
})
}}></input> <br/>
커피 가격 : <input type={"number"} value={coffee.price} onChange={(e) => {
setCoffee({
...coffee,
price: e.target.value
})
}}></input> <br/>
<button onClick={onClick}>추가!</button>
</div>
);
}
export default App;

추가를 클릭하면..~ Console 로그에 추가 되는게 보여지도록 하겠습니다.
아래의 코드를 살펴보면
const coffeeSelect = useSelector((state) => state.coffee);
이러한 코드를 마주치게 되는데!!.. 이건 무슨 뜻이냐 하면
/src/redux/store.js 에서 이 부분을 가리키게 됩니다!!
그래서 coffeeReducer를 지정해서 불러오겠다~.. 라고 생각하시면 되겠습니다.

전체 코드는 다음과 같습니다
/src/App.js
import { useSelector, useDispatch } from 'react-redux';
import { addCoffee } from './redux/actions/coffeeAction';
import { useState } from 'react';
function App() {
const coffeeSelect = useSelector((state) => state.coffee);
const dispatch = useDispatch();
let [coffee, setCoffee] = useState({
title: "",
price: 0
})
const onClick = () => {
dispatch(addCoffee(coffee));
alert("추가되었습니다!")
console.log(coffeeSelect);
}
...[이하 생략]
데이터를 입력해보고 추가!! 버튼을 눌러주면!!!
한개 한개 씩 추가되는것을 볼수가 있습니다!!

리코일 사용법
리코일의 경우, 리덕스보다 사용하기는 편리 합니다.
1. 라이브러리 설치
필요한 라이브러리 설치를 합시다.
npm install recoil
Recoil의 경우는 부모드리 어딘가에 `RecoilRoot` 가 필요합니다!
공식 홈페이지 에서는 Root 컴포넌트가 RecoilRoot를 넣기 가장 좋은 장소라고 하네요
저의 경우는 `src/index.js`에 넣어주었습니다.
import { RecoilRoot } from 'recoil';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<RecoilRoot>
<App />
</RecoilRoot>
);
2. 파일구조
리코일을 설정한 파일 구조는 다음과 같습니다.
📁 src
└─ 📁 recoil
└─ 📜 atom.js
└─ 📜 selector.js
3. Atom
Atom 사용법을 먼저 알아보도록 하겠습니다.
Atom은 상태(State)의 일부를 나타 냅니다. 어떤 컴포넌트에서나 읽고 쓸 수 있습니다.
하지만!.. Atom을 사용한 컴포넌트들은 구독 상태가 되어, State가 변화하면 구독된 컴포넌트들은 전부 렌더링이 되어버리는 상황이 발생합니다.
그러니.. 꼭 필요한 부분에만 하는것이 좋겠습니다!
Atom은 useState와 사용법이 유사하니, 금방 적응하실 수 있으실 겁니다.
// src/recoil/atom.js
import { atom } from "recoil";
export const upDownState = atom({
key: 'upDownState',
default: 0,
});
useRecoilState를 사용하면, useState처럼 사용할 수 있습니다.
// src/app.js
import { useRecoilState, useRecoilValue } from "recoil";
import { upDownState } from "./recoil/atom";
const App = () => {
let [updown, setUpDown] = useRecoilState(upDownState);
return (
<div>
<span>{updown}</span>
<br/>
<button onClick={() => {setUpDown(updown - 1)}}>down</button>
<button onClick={() => {setUpDown(updown + 1)}}>up</button>
</div>
)
}
export default App;

결과를 확인해봅시다 😊
See the Pen Recoil_atom by Kimjinwon (@hdev1004) on CodePen.
4. Selector
Selector의 경우는 Redux에서 Reducer와 같은 역할이라고 보시면 됩니다.
State의 변화되는 값을 통하여, 새로운 값의 형태로 만들어주는 좋은 기능 입니다.
많이는 사용할것 같지는 않지만 알아두는건 좋지요!
// src/recoil/selector.js
import { selector } from "recoil";
import { upDownState } from "./atom";
export const upDownSelector = selector({
key: 'upDownSelector', // unique ID (with respect to other atoms/selectors)
get: ({get}) => {
const updown = get(upDownState);
if(updown < 0) {
return `0 이하로는 내려갈 수 없습니다!`
}
return `값 : ${updown}`
},
});
import { useRecoilState, useRecoilValue } from "recoil";
import { upDownState } from "./recoil/atom";
import { upDownSelector } from "./recoil/selector";
const App = () => {
let [updown, setUpDown] = useRecoilState(upDownState);
let selector = useRecoilValue(upDownSelector);
return (
<div>
<span>{selector}</span>
<br/>
<button onClick={() => {setUpDown(updown - 1)}}>down</button>
<button onClick={() => {setUpDown(updown + 1)}}>up</button>
</div>
)
}
export default App;
이것도 결과를 확인해봅시다!
See the Pen Untitled by Kimjinwon (@hdev1004) on CodePen.
모두 즐거운 코딩 되세요 😊