[JS] 자바스크립트의 클로저

baegyeong·2024년 7월 28일

Java Script

목록 보기
6/9
post-thumbnail

코어자바스크립트 ch5. 클로저를 읽고 정리한 내용입니다.


클로저로 인한 메모리 누수와 관리

메모리 소모는 클로저의 본질적인 특성이다. 의도대로 설계한 ‘메모리 소모’에 대한 관리법만 잘 파악해서 적용하는 것으로 충분하다. (p.123)

useEffect

  • useEffect의 콜백함수는 클로저이다.
    • 의존성 배열을 통해 해당 상태가 변경될 때마다 useEffect의 콜백을 생성하도록 제어해야한다.
  • useEffect의 cleanup 함수
    • 해당 컴포넌트가 언마운트 될 때 실행된다.
    • useEffect의 setup 로직과 대칭이어야 하며, 셋업이 수행한 모든 작업을 중지하거나 취소해야 한다.
      • setup과 cleanup 함수의 예시
        setupcleanup
        setInterval()clearInterval()
        animation.start()anumation.reset()
    • 메모리 누수를 방지한다.
  • useEffect 동작
    1. 컴포넌트가 페이지에 마운트 될 때 setup 코드를 실행한다.
    2. 의존성 배열이 변경될 때마다
      • 이전 props와 state로 cleanup 코드를 실행한다.
      • 새 props와 setup으로 setup 코드를 실행한다.
    3. 컴포넌트가 페이지에서 언마운트되면 마지막으로 cleanup 코드를 실행한다.

console.log

  • 콘솔 출력은 메모리 누수의 원인이다.
function createLogger(msg) {
  let count = 0;
  return function() {
    count++;
    console.log(`${msg} ${count}`);
  };
}

let logger = createLogger("로그 메시지:");

// 이벤트 리스너에서 클로저 사용
document.getElementById("myButton").addEventListener("click", logger);
  • createLooger 함수는 클로저를 반환하며, 이때 내부 함수는 외부 변수를 참조한다.
  • 클릭 시마다 브라우저에 count가 저장되고, console.log에 의해 수거되지 않는다.
  • 개발환경에서는 디버깅 목적으로 사용할 수 있지만, 프로덕선 환경에서는 console.log를 제외하는 게 좋다.

커링함수

  • 커링함수는 함수를 호출하는 것이 아닌 변환하는 것이다.
  • 마지막 인자가 넘어갈 때까지 실행시간을 늦춘다.
  • 커링함수의 장점
    • 함수를 재사용하기 쉽다.
    • 모든 매개변수를 받을 때까지 함수 실행을 지연시킬 수 있다.
  • 커링함수를 언제, 어떻게 사용하는 게 좋을까?
    • 변동 가능성이 높은 인자일수록 뒷 순서로 받는 것이 좋다.
    • 고차컴포넌트
      // 커링 함수를 이용한 HOC 선언
      function withLoading(WrappedComponent) {
        return function({ isLoading, ...rest }) {
          if (isLoading) {
            return <div>Loading...</div>;
          } else {
            return <WrappedComponent {...rest} />;
          }
        };
      }
      
      // 예시 컴포넌트 선언
      function MyComponent({ data }) {
        return (
          <div>
            <h1>My Component</h1>
            <p>{data}</p>
          </div>
        );
      }
      
      // 사용 예시
      const MyComponentWithLoading = withLoading(MyComponent);
      
      function App() {
      	// 데이터를 가져오는 상태 시뮬레이션
        const [loading, setLoading] = useState(true);
        const [data, setData] = useState(null);
      
      	// ...
      
      	return (
      		<MyComponentWithLoading isLoading={loading} data={data} />
      	);
      }
      • 해당 컴포넌트를 사용할 때 로딩 상태를 함께 관리할 수 있다.
    • 성능 최적화
      const handleChange = (fieldName: string) => (
        e: React.ChangeEvent<
          HTMLInputElement | HTMLTextAreaElement
        >
      ) => {
        setValues({
          ...values,
          [fieldName]: e.currentTarget.value,
        });
      };
      
      return (
        <form onSubmit={handleSubmit}>
          <input
            type="text"
            placeholder="Enter your name"
            value={values.name}
            **onChange={handleChange("name")}**
          />
          <button type="submit">Save</button>
        </form>
      );
      • handleChange 함수를 일반 함수로 구현하면 onChange={()=>handleChange("name")} 형태인 익명함수를 전달해야 한다. 하지만 커링을 사용해서 더 간단하게 작성할 수 있다.
      • 각 이벤트마다 콜백을 만들기보다 핸들러에서 한 번만 만듦으로써 해결할 수 있다.

레퍼런스

당신이 모르는 자바스크립트의 메모리 누수의 비밀

useEffect

JavaScript 커링(Currying) 이해하기: 6가지 실전 활용 사례

0개의 댓글