Skip to content

[vanilla-store] useSetStore 훅이 불필요한 리렌더링을 유발 #178

@whddltjdwhd

Description

@whddltjdwhd

안녕하세요, 해당 글을 통해 vanilla-store에 흥미를 갖게 되었고 라이브러리를 사용해보니 매우 만족스러웠습니다. (무엇보다 Zero Dependency!!!)

한 가지, useSetStore 훅에 대한 작은 제안이 있어 이슈를 남깁니다. 현재 useSetStore가 스토어를 구독하여 리렌더링이 발생하는 것으로 보이는데, 이 부분에 대해 함께 논의해보면 어떨까 합니다.

원인

  • useSyncStore 함수 내부에서 useSyncExternalStore함수를 호출하여 현재 호출한 컴포넌트를 store에 구독한뒤 리액트 스케쥴러에 리렌더링을 예약하고, 현재 store의 snapshot을 반환합니다.
  • 이로 인해 useSetState를 호출하는 컴포넌트도 store값이 변경될 때마다 리렌더링이 발생합니다.
  • useSetStore는 set 함수에만 접근이 필요할 때 사용하는 훅입니다. 이 훅이 '쓰기 전용'으로 사용될 때 불필요한 리렌더링을 방지한다면, 라이브러리의 성능 최적화에 더 큰 도움이 될 것으로 보입니다!
export function useSetStore<State>(store: VanillaStore<State> | VanillaSelect<State>, initialValue?: State) {
    useSyncWithInitialValue(store, initialValue) 
    useSyncStore(store, initialValue) // 불필요한 상태 구독 중

    return store.set
}

해결 방안

  • useSetState에서 useSyncStore 함수 호출 코드를 삭제합니다.
  • 이로 인해 더이상 useSetStore를 사용중인 컴포넌트 함수는 리렌더링 되지 않습니다.
export function useSetStore<State>(store: VanillaStore<State> | VanillaSelect<State>, initialValue?: State) {
    useSyncWithInitialValue(store, initialValue) 
    // useSyncStore(store, initialValue) 삭제!!!!!

    return store.set
}

재현

  • 코드 샌드박스에서 브라우저 콘솔을 열고 나이 증가 버튼 또는 이름 입력 창에 글자를 타이핑하게 되면 <Input /> 컴포넌트 또한 리렌더링 되는 모습을 확인하실 수 있습니다.
Image

기타

  • 아직 라이브러리 전체를 이해하진 않았기에 제가 모르는 또다른 이유가 있거나 잘못 이해한 점이 있다면, 편히 알려주시면 감사하겠습니다!!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions