저번 글에서 selector에 대해서 이해가 가지 않아 연장선으로 글을 더 작성해보려 한다.
최소한의 상태 집합만 atoms에 저장하고 다른 모든 파생되는 데이터는 selectors에 명시한 함수를 통해 효율적으로 계산함으로써 쓸모없는 상태의 보존을 방지한다.
selector 은 readonly 한 값 만을 반환한다. 따라서 Recoil 을 활용할 때 수정 가능한 값을 반환 받고자 한다면 반드시 atom 을 활용해야 한다.
타입스크립트로 작성되었다.
function App() {
const [minutes, setMinutes] = useRecoilState(minuteState);
const [hours, setHours] = useRecoilState(hourSelector);
const onMinuteChange = (event: React.FormEvent<HTMLInputElement>) => {
const {
currentTarget: { value },
} = event;
setMinutes(+value);
};
const onHoursChange = (event: React.FormEvent<HTMLInputElement>) => {
const {
currentTarget: { value },
} = event;
setHours(+value);
};
return (
<div>
<input
onChange={onMinuteChange}
value={minutes}
type="number"
placeholder="Minutes"
></input>
<input
value={hours.toFixed(0)}
onChange={onHoursChange}
type="number"
placeholder="Hours"
></input>
</div>
);
}
export const minuteState = atom({
key: "minutes",
default: 0,
});
export const hourSelector = selector<number>({
key: "hours",
get: ({ get }) => {
const minutes = get(minuteState) / 60;
return minutes;
},
set: ({ set }, newValue) => {
// console.log(Number(newValue));
const minutes = Number(newValue) * 60;
set(minuteState, minutes);
},
});
export type status = "DONE" | "DOING";
interface toDo {
status: status;
contents: string;
}
export const selectStatus = atom<status>({
key: "nowStatus",
default: "DOING"
});
export const toDos = atom<toDo[]>({
key: "toDos",
default: [
{ status: "DOING", contents: "default 1" },
{ status: "DONE", contents: "default 2" },
{ status: "DONE", contents: "default 3" },
{ status: "DOING", contents: "default 4" },
{ status: "DOING", contents: "default 5" }
]
});
export const selectToDo = selector<toDo[]>({
key: "selectToDos",
get: ({ get }) => {
const originalToDos = get(toDos);
const nowStatus = get(selectStatus);
return originalToDos.filter((toDo) => toDo.status === nowStatus);
}
});
위 코드를 살펴보면 toDos 라는 atom 에 toDo 배열을 담아놨고, selector 을 통해서 변화된 값을 리턴받아 사용하고 있다.
selector 의 구조를 살펴보면, atom 과 다른 부분이 있다. 위 코드에서 바로 get 이라는 코드를 살펴볼 수 있는데, selector 은 내부적으로 함수에서 get 을 반환 해주며 get 메서드를 활용해 현재 저장된 atom 이나 다른 selector 의 값을 받아올 수 있다. 이를 통해서 atom 을 input 받고 원하는 결과를 위해 배열을 변형해 output 해줍니다.
export default function App() {
const [status, setStatus] = useRecoilState(selectStatus);
const selectToDos = useRecoilValue(selectToDo);
const handleStatus = (event: React.ChangeEvent<HTMLSelectElement>) => {
setStatus(event.currentTarget.value as any);
};
return (
<>
<div>
<select value={status} onChange={handleStatus}>
<option value="DOING">DOING</option>
<option value="DONE">DONE</option>
</select>
<ul>
{selectToDos.map((toDo, index) => {
return (
<li key={index}>
<span>status: {toDo.status}</span>
<br />
<span>content: {toDo.contents}</span>
</li>
);
})}
</ul>
</div>
</>
);
}
UI 컴포넌트로 select 태그를 활용해 status atom 을 변경해주고 있으며, selector 을 통해서 toDo 배열을 화면에 뿌려주고 있다.
참조
https://hell-of-company-builder.tistory.com/m/225
https://tech.osci.kr/2022/06/16/recoil-state-management-of-react/