react의 상태관리 라이브러리인 recoil은 컴포넌트간 상태 공유라는 기본적인 기능 외에도 selector와 같은 유용한 기능들도 많이 제공하고 있다. 이번에는 selector에 대해 공부해볼겸 간단한 예제도 만들어보려고 한다.
selector는 쉽게 말해서 기존에 선언한 atom을 전/후 처리하여 새로운 값을 리턴하거나 기존 atom의 값을 수정하는 역할을 수행한다. 그리고 참조한 atom의 값이 최신화되면 자동으로 selector의 값도 최신화하므로, 관리하기에도 간편하다.
export const sampleState = atom({
key: "sampleState",
default: 0,
});
export const sampleSelector = selector({
key: "sampleSelector",
get: ({ get }) => get(sampleState) * 2,
set: ({ set }, newValue) => set(sampleState, newValue / 2),
});
가장 기본적인 예제를 한번 만들어봤다. sampleSelector는 sampleState를 참조해 sampleState * 2 라는 값을 리턴하고 있다. 또한 setter를 보면 새롭게 입력된 값을 나누기 2 하여 sampleState에 적용하고 있음을 볼 수 있다. 이처럼 selector를 이용하면 기존에 선언한 atom들을 참조하여 새로운 값을 만들어내고, 새롭게 입력받은 값을 후처리하여 atom의 값까지도 수정하도록 설정할 수 있다.
사용방법 또한 아주 간단한데, atom을 사용할 때와 마찬가지로 useRecoilState를 사용하면 된다.
const [sample,setSample] = useRecoilState(sampleState);
const [sample2,setSample2] = useRecoilState(sampleSelector)
실제로 불러와 사용하는 것만 봐서는 selector와 atom이 구분되지 않는다.
selector를 활용하기에 쉽게 생각해볼 수 있는 예제가 바로 이번에 구현하려고 하는 '환전'시스템이다. 각국의 통화들은 모두 완전히 독립되어 있지 않으며, 환율이라는 계수에 의해 언제든 상호 변환될 수 있기 때문이다. 따라서 각국의 통화에 해당하는 별개의 atom을 만들어 매번 최신화하기보다, 기준이 되는 통화를 설정하고 해당 통화로부터 다른 통화의 가치를 계산하여 사용하는 편이 훨씬 간편할 것이다.
현재 원달러 환율이 대략 1400원 정도라고 가정하면 아래와 같이 코드를 구성할 수 있다.
import { atom, selector } from "recoil";
export const wonState = atom({
key: "wonState",
default: 0,
});
export const dollarState = selector({
key: "dollarState",
get: ({ get }) => get(wonState) / 1400,
set: ({ set }, dollar) => set(wonState, dollar * 1400),
});
이제 준비는 다 끝났으니 react를 사용해 기본적인 ui를 그리고 연동해보자.
//Won.js
import React, { useEffect, useState } from "react";
import { useRecoilState } from "recoil";
import { wonState } from "../atom/store";
const Won = () => {
const [won, setWon] = useRecoilState(wonState);
const [text, setText] = useState("");
const onChange = (e) => {
setText(e.target.value);
};
useEffect(() => {
setText(won);
}, [won]);
return (
<div>
원화를 입력해주세요.
<input value={text} onChange={onChange} />
<button
onClick={() => {
setWon(Number(text));
}}
>
환전하기
</button>
</div>
);
};
export default Won;
//Dollar.js
import React, { useEffect, useState } from "react";
import { useRecoilState } from "recoil";
import { dollarState } from "../atom/store";
const Dollar = () => {
const [ dollar, setDollar ] = useRecoilState(dollarState);
const [text, setText] = useState("");
const onChange = (e) => {
setText(e.target.value);
};
useEffect(() => {
setText(dollar);
}, [dollar]);
return (
<div>
달러를 입력해주세요.
<input value={text} onChange={onChange} />
<button
onClick={() => {
setDollar(Number(text));
}}
>
환전하기
</button>
</div>
);
};
export default Dollar;
//App.js
import Won from "./components/Won";
import Dollar from "./components/Dollar";
import React from "react";
const App = () => {
return (
<div>
<Won />
<Dollar />
</div>
);
};
export default App;
잘 동작한다. (뿌듯)
const { dollar, setDollar } = useRecoilState(dollarState); 오타났어용