react로 개발을 하다보면, 점점 상태관리를 하는 코드가 늘어나기 마련이다.
특히 useState
를 난무하는 경우가 발생하며, react의 특성 중 하나인 ‘단방향 데이터 흐름’으로 인해 useState
로 상태가 변경된 값을 props
를 특정 컴포넌트로 계속 전달 → 전달 → 전달하는 방식이 된다.
즉, 복잡한 상태 관리를 위해 여러 개의 useState
를 사용해야 하기 대문에 상태가 복잡해지면 코드가 길어지면서, 컴포넌트 계층 구조가 깊어질수록 상태 전달이 번거롭다는 단점이 발생한다.
나는 이러한 상태관리의 복잡성과 번거로움에 지쳐 이를 해결하고자 Recoil
사용을 도입하였다.
Recoil
장점:
useState
와 유사하게 생겼으며 [get, set]
기능 또한 동일하여 쉽게 접근할 수 있음// useState
const [id, setId] = useState(0);
// recoil
const [count, setCount] = useRecoilState(countState);
<RecoilRoot>
를 사용해야함 - 보통 전역으로 사용하므로 루트 컴포넌트에 넣는게 좋음import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { RecoilRoot } from 'recoil';
ReactDOM.render(
<React.StrictMode>
<RecoilRoot>
<App />
</RecoilRoot>
</React.StrictMode>,
document.getElementById('root')
);
Recoil의 경우, 공식 문서에서 예시 코드를 잘 보여주고 있다.
쉽게 말해 react의 단방향 데이터 흐름 특성으로 인해 생기는 불편함을 해소시켜준다.
useState를 사용하는 경우, 상태 전달이 번거로웠지만, atom을 이용하여 해당 상태 구조를 정의해주기만 하면, 그 상태를 어느 컴포넌트에서도 쉽게 접근할 수 있다.
key
: atom을 식별하는데 필요한 고유한 문자열default
: 초기값export const todoListState = atom({
key: 'TodoList',
default: [],
});
useState
와 비교// useState
const [id, setId] = useState(0);
// atom으로 상태 구조
export const idState = atom({
key: 'idStateKey',
default: 0,
});
//recoil
const [id, setId] = useRecoilState(idState);
atom
을 전/후 처리하여 새로운 값을 반환하거나 기존 atom
값을 수정하는 역할 수행Selector: derived state(파생된 상태)를 나타내는데 사용
파생된 상태란 기본 상태를 입력으로 받아 변환된 값을 출력하는 상태
key
: 고유한 문자열get
: 다른 atom이나 selector의 상태를 읽는 데 사용set
: atom의 상태를 설정하거나 업데이트하는 데 사용// 사용자의 입력을 저장하는 atom
const textState = atom({
key: 'textState', // 고유한 키
default: '', // 기본값
});
// 텍스트의 길이를 계산하는 selector
// set 함수: 입력된 텍스트를 대문자로 변환하여 atom을 업데이트
const textLengthSelector = selector({
key: 'textLengthSelector',
get: ({get}) => {
const text = get(textState);
return text.length;
},
set: ({set}, newValue) => {
// 예를 들어, 텍스트를 대문자로 변경
const upperCaseText = newValue.toUpperCase();
set(textState, upperCaseText);
}
});
// import문은 생략
function TextComponent() {
const [text, setText] = useRecoilState(textState);
const textLength = useRecoilValue(textLengthSelector);
return (
<div>
<input type="text" value={text} onChange={(e) => setText(e.target.value)} />
<p>Text Length: {textLength}</p>
</div>
);
}