안녕하세요. 리액트 컴포넌트와 자바스크립트 스코프가 엮인 문제에 대해 질문 드립니다!

안녕하세요, 평소에 글 작성 없이 조회만 하다가 기초적인 부분에 대해 여쭤보고자 글 작성하게 되었습니다!

평소라면 onIncrement 함수를 Home 컴포넌트 내부에 선언해서 사용했을텐데 문득 ‘이렇게 작성하면 안될 이유가 뭐지?’ 라는 생각이 들었고 그런데 이걸 제대로 설명하지 못하는 제 자신을 발견했습니다.

아래엔 제가 질문을 드리고 싶은 부분에 대한 코드가 있습니다.

import React, { useState } from "react";

function onIncrement(setCount2: any) {
  setCount2((prev: any) => prev + 1);
}

function Home() {
  const [count, setCount] = useState(0);
  return <div onClick={() => onIncrement(setCount)}>{count}</div>;
}

export default Home;

위의 코드에서 click event가 발생해서 onIncrement가 콜스택에 올라가고 호출되면

자바스크립트 엔진은 onIncrement 선언부 내부로 이동하는 것으로 알고 있습니다.

그럼 선언부 내부에서 매개 변수 setCount2가 useState의 setCount로 복사되는 시점도 호출되는 시점이 맞는 걸까요?

정리해보면 제 질문은…

onIncrement가 호출된다 => 선언부로 간다 => setCount2를 호출한다.
이때, setCount2는 언제 결정되는 것일까요?


안티 패턴이라던가 드러나지 않는 문제가 위의 코드에 존재하는지도 궁금합니다.

원석님, 반가워요~ .

현재 코드 상에서는 동작하는데는 아무 문제 없습니다.
하지만 올려주신 구조로 가야하려고 한 "이유"에 따라 얘기 나눠볼 수 있는 포인트가 달라집니다.

:question:역으로 제가 질문 드려보자면 onIncrement 을 밖으로 뺀 이유가 무엇인가요? 재사용? 가독성? 성능?

예를 들어 onIncrement 처럼 현재의 값을 그 기준으로 숫자가 변하는 로직(특히 복잡하며 재사용 될 가능성 있는 경우)의 재사용이라면 아래와 같이 하는 게 increment를 순수하게 유지하게 되겠죠.

const increment = pre => pre +1;
<div onClick={() => setCount(increment)}>

올려주신 코드만을 봤을 때는 onIncrement가 setCount2의 입력을 만들어서 실행해주는 역할만 합니다. onIncrement가 입력으로 받은 setCount2의 입력을 만들어서실행까지 해주는 현재 코드보다는

  • 재사용하려는 함수 자체가 입력이 되거나(바로 위 제 코드)
  • 그 함수의 return값이 입력에 사용될 수 있도록 해서
    setCount가 선언된 곳에서 setCount를 호출되도록 하는 게 재사용하려고 분리한 함수(로직)과 count 및 setCount의 관심사가 완전히 분리됩니다.

혹시 다른 고려한 이유가 있다면 알려주세요. :wink:

예시로 첨부한 onIncrement가동작에는 문제 없으나 단순히 setCount를 전달받아 입력만 만들어주는 역할만 하므로, 어떻게 보면 setCount에 의존성이 생기는 것이군요!

오히려 입력으로 넣던 함수를 재사용하면 재사용성도 좋아지고 count setCount와도 관심사 분리가 되므로 코드 관리 측면에서도 좋아지겠구요!

밖으로 뺐더 이유는… 습관적으로 컴포넌트 내부에서 관련 함수를 선언해서 사용하다보니 이렇게 하는 것은 왜 안될까? 라는 생각이 들어 질문을 드렸던거 같습니다!

덕분에 어떤 것이 문제인지 명확히 이해되었습니다 :slight_smile: