Recoil (2)

BirdsOnTree·2022년 10월 19일
0

React

목록 보기
9/10
post-thumbnail

저번 글에서 selector에 대해서 이해가 가지 않아 연장선으로 글을 더 작성해보려 한다.

selector

Selector 을 사용해야 하는 이유

최소한의 상태 집합만 atoms에 저장하고 다른 모든 파생되는 데이터는 selectors에 명시한 함수를 통해 효율적으로 계산함으로써 쓸모없는 상태의 보존을 방지한다.

  • get - 파생된 상태의 값을 평가하는 함수. 값을 직접 반환하거나 비동기적인 Promise나 또는 같은 유형을 나타내는 다른 atom이나 selector를 반환할 수 있다. 첫 번째 매개변수로 다음 속성을 포함하는 객체를 전달한다
  • set? - 이 속성이 설정되면 selector는 쓰기 가능한 상태를 반환한다. 첫번째 매개변수로 콜백 객체와 새로 입력 값이 전달된다. 사용자가 selector를 재설정할 경우 새로 입력 값은 T 타입의 값 또는 DefaultValue 타입의 객체일 수 있다. 콜백에는 다음이 포함된다.

selector 은 readonly 한 값 만을 반환한다. 따라서 Recoil 을 활용할 때 수정 가능한 값을 반환 받고자 한다면 반드시 atom 을 활용해야 한다.

예시 1

타입스크립트로 작성되었다.

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);
  },
});
  1. minuteState에서 분의 입력을 받아서 저장
  2. hourSelector에서 먼저 get 함수로 minutesState 값을 가져온 후 값/60 을 하여 minutes 리턴
  3. set함수에서는 hours input에 입력되는 값을 인지한 뒤 newValue 값을 받아 60을 해주어 minute 값을 리턴하여 set(변하고자하는 atom값 , 변하게 할 값) 을 이용하여 set(minuteState , minutes)를 하였다.
  4. const [hours,setHours] = useRecoilState(hourSelector) 에서 hours에서는 get 리턴을 받는다.
  5. setHours 에서는 Selector 안의 set에서의 시간을 분으로 바꾸는 함수를 실행해준다.

예시 2

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 을 통해서 변화된 값을 리턴받아 사용하고 있다.

  1. selector에서 get으로 toDos의 default 배열이 originalToDos에 담긴다.
  2. selector에서 get으로 selectStatus의 default "DOING"이 nowStatus에 담긴다.
  3. originalToDos의 status가 "DOING"인것을 return 해준다.

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/

0개의 댓글