jotai의 "1000 컷으로 사망"성능 문제를 피하십시오.

문제



나는 Rich Harris의 this blog post "1000 컷으로 사망"이라는 React의 성능 문제를 파악하기가 정말 어렵다는 것을 처음 알았습니다.

The danger of defaulting to doing unnecessary work, even if that work is trivial, is that your app will eventually succumb to 'death by a thousand cuts' with no clear bottleneck to aim at once it's time to optimize.



그것이 무엇을 의미하는지 알아보자. 파생된 React 상태와 관련된 가장 간단한 패턴을 살펴보겠습니다. 두 개의 숫자 추가하기.

const Component = (props) => {
  const [n, setN] = useState(1)
  const [m, setM] = useState(1)
  const sum = n + m
  ...
}


이 코드 조각만 보면 전혀 문제가 없어 보입니다. 이 구성 요소는 원활하게 작동하며 성능에는 전혀 문제가 없습니다.

React 렌더링 중에 어떤 일이 일어나고 이것이 "1000 컷에 의한 죽음"에 어떻게 기여하는지 관찰합시다.

React 구성 요소는 상태 또는 소품 변경 시 다시 렌더링됩니다. 다시 렌더링할 때마다 React 구성 요소의 함수 본문이 실행됩니다. 따라서 모든 재렌더링에서 추가( n + m )가 실행되고 추가 결과에 영향을 주지 않는 상태 또는 소품 변경이 발생할 때도 실행됩니다.

언뜻보기에 이것은 전혀 중요하지 않습니다. 불필요하더라도 매번 추가를 재평가하는 것은 문제가 되지 않습니다. 불필요한 재평가를 방지하기 위해 다음을 수행할 수 있습니다.

const sum = useMemo(() => n + m, [n, m])


하지만 잠깐, 우리는 값비싼 계산을 통해서만 그렇게 해야 합니다. 맞죠? 그리고 간단한 추가는 거의 가장 저렴한 것입니다.

그래서 우리는 그러한 진술을 암기하지 않고 약간의 불필요한 추가 작업을 수락합니다. 우리는 "작은 작은 컷"을 받아들입니다. 그들 중 하나 또는 몇 개는 큰 해를 끼치 지 않습니다.

그러나 코드베이스가 성장하고 그러한 "컷"이 계속해서 1000까지 추가됨에 따라, 어느 시점에서 UI가 느려지고 느려질 수 있으며 왜 그것이 무엇이고 무엇을 잘못했는지 전혀 모를 수 있습니다(실제로 아무 잘못도 하지 않았기 때문에) .

그런 다음 "1000 컷으로 사망"성능 문제가 발생합니다.

치유법


useMemo 를 사용하여 코드베이스 전체에서 파생된 상태를 메모하기 시작합니다. 어디서 시작해야 하고 언제 시작해야 하는지에 대한 명확한 표시가 없습니다. 이 작업을 수행한 후 어느 시점에서 성능은 다시 정상이 될 것입니다. 애플리케이션이 더 커지면 다시 팝업될 수 있으며 프로세스를 반복해야 합니다.

구원



jotai 원자로 상태 패턴을 상향식으로 디자인하십시오. 그렇다면이 문제는 의도적으로 나타날 기회가 없습니다!

원자인 jotai의 핵심 추상화와 이를 사용하여 상태 패턴을 구축하는 방법을 자세히 살펴보겠습니다. jotai를 사용하여 위의 추가를 모델링하는 방법을 살펴보겠습니다.

const nAtom = atom(1)
const mAtom = atom(1)
const sumAtom = atom((get) => get(nAtom) + get(mAtom))

const Component = (props) => {
  const [n, setN] = useAtom(nAtom)
  const [m, setM] = useAtom(mAtom)
  const sum = useAtom(sumAtom)
  ...
}


이 구성 요소는 위의 useState가 있는 스니펫과 동일하게 작동합니다. 한 가지 차이점이 있습니다. sum는 n 또는 m이 변경될 때만 재평가됩니다. 따라서 useMemo는 일종의 "내장"입니다.

이러한 원자 선언과 그 의미를 살펴보겠습니다. nAtommAtom는 소위 "원시 원자"입니다. 단일 숫자에 대해 읽고 쓸 수 있는 컨테이너입니다. useAtom를 사용하면 useState가 제공하는 것과 동일한 인터페이스를 사용하여 React 구성 요소 내에서 이 컨테이너와 상호 작용할 수 있습니다.
sumAtom는 소위 "유도 원자"입니다. nAtommAtom 의 현재 값을 합한 읽기 전용 컨테이너입니다. 이 컨테이너는 종속성( nAtom , mAtom ) 중 하나가 변경될 때만 값을 재평가해야 한다는 것을 "알고 있습니다". 이러한 종속성은 get 함수로 추적됩니다. useAtom를 사용하면 React 구성 요소 내에서 이 컨테이너와 상호 작용하고 파생된 값(합계)을 직접 얻을 수 있습니다.

이러한 상향식 방식으로 원자로 상태를 설계함으로써 우리는 항상 상태에 대한 최소한의 "종속성/데이터 흐름 그래프"로 끝납니다. 여기서 파생된 상태는 (전이적) 종속성 중 하나가 변경되는 경우에만 재평가됩니다.

너무 화려하게 들린다면 기본적으로 스프레드시트와 동일합니다. "atom"을 "cell"로 바꾸면 됩니다 😉

우리는 항상 필요한 최소한의 작업만 합니다. "컷"이 발생하지 않습니다.

좋은 웹페이지 즐겨찾기