[ 살펴보기 ] Jotai - Utility

[ 살펴보기 ] Jotai - Utility

·

3 min read

Jotai는 앞선 포스트에서 살펴본 Jotai의 기본적인 기능외에 활용할 수 있는 Utility를 제공한다. 이번 포스트에서는 Jotai가 제공하는 Utility에 대해 살펴보자

Resettable Atom

Resettable atom은 초기 값을 기억하고 있다가 useResetAtom hook을 통해 다시 초기값으로 되돌린다

import { atomWithReset, useResetAtom } from "jotai/utils";

const countAtom = atomWithReset(0);

const UserJotai = () => {
  const [count, setCount] = useAtom(countAtom);
  const resetCountAtom = useResetAtom(countAtom);
  return (
    <div>
      <h3>UserJotai</h3>
      <div>{count}</div>
      <div
        onClick={() => {
          setCount(count + 1);
        }}
      >
        <button>Increase</button>
      </div>
      <div>
        <button onClick={resetCountAtom}>Reset</button>
      </div>
    </div>
  );
};

위의 예제를 살펴보자. 우선 atomWithReset를 통해 resettable atom을 생성하여 사용하고 있으며 useResetAtom에 countAtom resettable atom을 전달하였다. 그리고 이제 resetCountAtom 함수를 발생시키면 countAtom은 초기값이였던 0으로 돌아간다

만약 다른 atom 값을 default로 하는 resettable atom을 만들고자 한다면 atomWithDefault util을 사용할 수 있다

import {
  atomWithDefault,
  atomWithReset,
  useResetAtom,
} from "jotai/utils";

const countAtom = atomWithReset(0);
const resettableCountAtom = atomWithDefault((get) => get(countAtom) + 1);

const UserJotai = () => {
  const [count, setCount] = useAtom(resettableCountAtom);
  const resetCountAtom = useResetAtom(resettableCountAtom);
  ...
}

위의 예제에서 resetCountAtom을 실행시키면 resettableCountAtom의 초기 값인 1로 돌아간다

atomWithRefresh

atomWithRefresh를 통해 atom의 read logic을 재실행 하여 값을 refresh할 수 있는 atom을 만들 수 있다. 다음의 예를 살펴보자

import {
  atomWithRefresh,
} from "jotai/utils";

let testCount = 10;

const countAtom = atomWithRefresh((get) => {
  return testCount;
});

const UserJotai = () => {
  const [count, refreshCount] = useAtom(countAtom);
  return (
    <div>
      <h3>UserJotai</h3>
      <div>{count}</div>
      <div
        onClick={() => {
          testCount++;
        }}
      >
        <button>Increase</button>
      </div>
      <div>
        <button
          onClick={() => {
            refreshCount();
          }}
        >
          Refresh
        </button>
      </div>
    </div>
  );
};

위의 예제에서 Increase 버튼을 누르면 testCount 값이 상승하고 이후 refresh 버튼을 누르면 countAtom의 read function이 재실행되며 새로운 값이 설정된다. 위의 예제에서는 단순히 변수의 값을 가져오고 있지만 특정 데이터를 fetch해서 가져와야 할 때도 유용하게 사용할 수 있다.

useSplitAtom

List 형식의 데이터를 관리하는 atom을 기준으로 list item을 각각의 새로운 atom으로 관리하고 싶을 때 유용하게 쓸 수 있다. 다음 예제를 살펴보자

const todoList = [
  {
    title: "help the town",
    done: false,
  },
  {
    title: "feed the dragon",
    done: false,
  },
];

const todosAtom = atom(todoList);
const todoSplitAtom = splitAtom(todosAtom);

export type TodoAtomType = (typeof initialState)[0];

const TestJotai = () => {
  const [todoAtoms, dispatch] = useAtom(todoSplitAtom);

  return (
    <div>
      {todoAtoms.map((todoAtom) => (
        <TestJotaiSplitItem
          todoAtom={todoAtom}
          remove={() => dispatch({ type: "remove", atom: todoAtom })}
        />
      ))}
    </div>
  );
};

export default TestJotai;

위의 예제에서 우리는 splitAtom(todosAtom)을 통해 split된 각가의 atom을 TestJotaiSplitItem componen에 전달하고 있다. splitAtom을 통해 return된 atom을 사용하면 위와 같이 dispatch 함수를 사용할 수 있는데 remove, insert, move와 같이 original atom을 보다 쉽게 변경할 수 있도록 도와준다. 위의 예제에선 remove prop을 통해 remove event가 발생하면 해당 item이 삭제되도록 처리하고 있다.

이제 넘겨받은 atom을 사용하는 TestJotaiSplitItem component를 살펴보자

// TestJotaiSplitItem.tsx

import { TodoAtomType } from "../page";
import { PrimitiveAtom, useAtom } from "jotai";
import React from "react";

type Props = {
  todoAtom: PrimitiveAtom<TodoType>;
  remove: () => void;
};

const TestJotaiSplitItem = ({ remove, todoAtom }: Props) => {
  const [todo, setTodo] = useAtom(todoAtom);
  return (
    <div>
      <input
        value={todo.task}
        onChange={(e) => {
          setTodo((preValue) => ({ ...preValue, task: e.target.value }));
        }}
      />
      <button onClick={remove}>remove</button>
    </div>
  );
};

export default TestJotaiSplitItem;

예제에서 볼 수 있듯이 split된 atom을 넘겨받아 일단 atom을 사용하듯이 사용할 수 있다. 만약 위의 예제에서 input 값이 변경된다면 해당 component에서 사용하고 있는 atom 뿐만 아니라 parent component에서 선언되어 있던 original atom 역시 변경된다.