[Core] - useAtom

강 진성·2024년 3월 25일
0

Jotai

목록 보기
3/5

useAtom


useAtom 후크는 상태의 원자 값을 읽는 것입니다. 상태는 원자 구성 및 원자 값의 WeakMap으로 볼 수 있습니다

useAtom 후크는 React의 useState와 마찬가지로 원자 값과 업데이트 함수를 튜플로 반환합니다. atom()으로 생성된 Atom 구성이 필요합니다.

처음에는 Atom과 관련된 값이 없습니다. useAtom을 통해 Atom이 사용된 경우에만 초기 값이 상태에 저장됩니다. Atom이 파생 Atom인 경우 읽기 함수가 호출되어 초기 값을 계산합니다. Atom이 더 이상 사용되지 않으면 이를 사용하는 모든 구성 요소가 마운트 해제되고 Atom 구성이 더 이상 존재하지 않으며 상태의 값은 가비지 수집됩니다.


const [value, setValue] = useAtom(anAtom)

`setValue`는 단 하나의 인수만 취하며, 이는 원자 쓰기 함수의 세 번째 인수로 전달됩니다. 동작은 쓰기 기능이 구현되는 방식에 따라 달라집니다.

참고 : atom 섹션에서 언급한 대로 atom 참조를 처리해야 합니다. 그렇지 않으면 무한 루프에 빠질 수 있습니다.


const stableAtom = atom(0)
const Component = () => {
  const [atomValue] = useAtom(atom(0)) // 무한 루프가 발생합니다. 
									   // (atom을 직접적으로 쓰지말라는 뜻?)
																		   
  const [atomValue] = useAtom(stableAtom) // 이것은 괜찮습니다.
  const [derivedAtomValue] = useAtom(
    useMemo(
      // 이것 또한 괜찮습니다.
      () => atom((get) => get(stableAtom) * 2),
      [],
    ),
  )
}

참고 : React는 컴포넌트 호출을 담당한다는 점을 기억하세요. 즉, 멱등성이 있어야 하고 여러 번 호출할 준비가 되어 있어야 합니다. Prop이나 Atom이 변경되지 않은 경우에도 추가로 다시 렌더링되는 경우가 종종 있습니다. 커밋 없이 추가로 다시 렌더링하는 것은 예상되는 동작입니다. 이는 실제로 React 18에서 useReducer의 기본 동작입니다.


사용 예시

// store.ts
export const emailValid = atom(false); // 이메일 유효성
export const emailAtom = atom(''); // 이메일 입력값

atom 만 모아둔 store.ts 에서 import 해온다.


import { useAtom } from 'jotai';
import { emailAtom, emailValid } from '@/stores/stores';

// EmailComponent props의 타입 선언
interface EmailComponentProps {
  label?: boolean;
  error?: boolean;
  valid?: boolean;
  style?: string;
}

function EmailComponent({ label, error, style, valid = false }: EmailComponentProps) {
	const [, setEmailValid] = useAtom(emailValid); // 이메일 유효성 체크
  const [emailValue, setEmailValue] = useAtom(emailAtom); // 이메일 값


Signatures


// 원시 또는 쓰기 가능한 파생 atom
function useAtom<Value, Update>(
  atom: WritableAtom<Value, Update>,
  options?: { store?: Store },
): [Value, SetAtom<Update>]

// 읽기 전용 atom
function useAtom<Value>(
  atom: Atom<Value>,
  options?: { store?: Store },
): [Value, never]

useAtom 후크는 공급자에 저장된 원자 값을 읽는 것입니다. useState와 마찬가지로 원자 값과 업데이트 함수를 튜플로 반환합니다. Atom()으로 생성된 Atom 구성이 필요합니다. 처음에는 공급자에 저장된 값이 없습니다.
useAtom을 통해 Atom이 처음 사용되면 Provider에 초기 값이 추가됩니다. 원자가 파생 원자인 경우 읽기 함수가 실행되어 초기 값을 계산합니다.
Atom이 더 이상 사용되지 않으면 이를 사용하는 모든 구성 요소가 마운트 해제되고 Atom 구성이 더 이상 존재하지 않으며 해당 값이 공급자에서 제거됩니다.


const [value, setValue] = useAtom(anAtom)

setValue는 하나의 인수를 취하며, 이는 원자의 writeFunction의 세 번째 인수로 전달됩니다. 동작은 writeFunction이 구현되는 방식에 따라 달라집니다.



How atom dependency works


시작하기에 앞서, 우선 이것을 설명해봅시다. 현재 구현에서는 "읽기" 기능을 호출할 때마다 종속성과 종속 항목을 새로 고칩니다. 예를 들어, A가 B에 종속된 경우 B는 A의 종속성이고 A는 B의 종속성을 의미합니다


const uppercaseAtom = atom((get) => get(textAtom).toUpperCase())

읽기 기능은 원자의 첫 번째 매개변수입니다. 종속성은 처음에는 비어 있습니다. 처음 사용할 때 읽기 기능을 실행하고 uppercaseAtomtextAtom에 의존한다는 것을 알게 됩니다. textAtomuppercaseAtom에 종속됩니다. 따라서 textAtom의 종속 항목에 uppercaseAtom을 추가하세요. 읽기 기능을 다시 실행하면(종속성 textAtom이 업데이트되었기 때문에) 종속성이 다시 생성됩니다. 이 경우에도 마찬가지입니다. 그런 다음 오래된 종속 항목을 제거하고 최신 항목으로 교체합니다.



Atoms can be created on demand


여기의 기본 예에서는 구성 요소 외부에서 전체적으로 원자를 정의하는 것을 보여 주지만 원자를 생성할 수 있는 위치와 시기에 대한 제한은 없습니다. 원자가 객체 참조 ID로 식별된다는 점을 기억하는 한 언제든지 원자를 생성할 수 있습니다

렌더링 함수에서 원자를 생성하는 경우 일반적으로 메모를 위해 useRef 또는 useMemo와 같은 후크를 사용하고 싶을 것입니다. 그렇지 않으면 구성 요소가 렌더링될 때마다 원자가 다시 생성됩니다.

전역적으로 어딘가에 원자를 캐시할 수 있습니다. 예시를 참조하십시오.

매개변수화된 원자에 대해서는 유틸리티에서 atomFamily 를 확인하세요



useAtomValue


const countAtom = atom(0)

const Counter = () => {
  const setCount = useSetAtom(countAtom)
  const count = useAtomValue(countAtom)

  return (
    <>
      <div>count: {count}</div>
      <button onClick={() => setCount(count + 1)}>+1</button>
    </>
  )
}

useSetAtom 후크와 유사하게 useAtomValue를 사용하면 읽기 전용 Atom에 액세스할 수 있습니다.



useSetAtom


const switchAtom = atom(false)

const SetTrueButton = () => {
  const setCount = useSetAtom(switchAtom)
  const setTrue = () => setCount(true)

  return (
    <div>
      <button onClick={setTrue}>Set True</button>
    </div>
  )
}

const SetFalseButton = () => {
  const setCount = useSetAtom(switchAtom)
  const setFalse = () => setCount(false)

  return (
    <div>
      <button onClick={setFalse}>Set False</button>
    </div>
  )
}

export default function App() {
  const state = useAtomValue(switchAtom)

  return (
    <div>
      State: <b>{state.toString()}</b>
      <SetTrueButton />
      <SetFalseButton />
    </div>
  )
}

원자 값을 읽지 않고 업데이트해야 하는 경우 useSetAtom()을 사용할 수 있습니다.

이는 성능이 중요할 때 특히 유용합니다. const [, setValue] = useAtom(valueAtom)은 각 valueAtom 업데이트에서 불필요한 다시 렌더링을 유발하기 때문입니다



참고 자료


https://jotai.org/docs/core/use-atom

profile
완전완전완전초보초보초보

0개의 댓글