어제의 나보다 성장한 오늘의 나

[React] 클래스 인스턴스의 효율적인 렌더링과 접근 범위 제어 방법 본문

React

[React] 클래스 인스턴스의 효율적인 렌더링과 접근 범위 제어 방법

today_me 2024. 3. 24. 23:49
반응형

 

 

 

 리액트에서 클래스를 설계하고 컴포넌트 내에서 클래스 인스턴스를 활용하는 코드를 작성하였는데, 더 효율적으로 관리하는 방법을 배우게 되어 공유하고 싶은 마음에 글을 작성하게 되었습니다.

 

 


 

 

두 가지에 초점을 맞췄습니다

1) 인스턴스의 불필요한 재렌더링 방지
2) 인스턴스의 전역적인 접근 막기 ( 사이드 이펙트 방지 차원 )

 

 

 

1. 처음 작성했던 클래스 방식 ( 예시 코드 )

 

 

calculator.js

export class Calculator {

  add(a, b) {
    return a + b;
  }

  multiply(a, b) {
    return a * b;
  }
  
}

 

 

 

page.jsx

export default function Page(){

    const [first , setFirst] = useState(1);
    const [second , setSecond] = useState(2);
    const [result , setResult] = useState(0);
    const calculator = new Calculator();
    
    useEffect( () => {
        setResult(calculator.add(1+2));
    } , [first , second])

    return (
        <>
            {result}
        </>
    )
}

 

 

 

문제점

 

page가 재랜더링 될 때마다 calculator의 인스턴스가 새로 생성되게 된다. (불필요한 재렌더링)

 

 

 

 

 

2.  싱글톤 클래스 사용

 

싱글톤을 사용하여 하나의 인스턴스만 활용하여 메모리 누수를 방지

 

 

 

calculator.js

export class Calculator {
  static instance = null;

  constructor() {
    if (Calculator.instance) {
      return Calculator.instance;
    }
    Calculator.instance = this;
  }

  static getInstance() {
    if (!Calculator.instance) {
      Calculator.instance = new Calculator();
    }
    return Calculator.instance;
  }

  ...
}

 

 

 

문제점

 

이 instance는 전역적으로 접근이 가능하다. ( 사이드 이펙트 위험 가능성 )

 

그리고 다른 페이지에서 다른 인스턴스를 사용하고 싶어도 그럴 수 없다.

독립적인 인스턴스 사용이 불가능하다 ㅠㅠ

 

 

 

3. 컨텍스트의 활용

 

컨텍스트를 활용해서 접근 범위를 제한 한다.

 

 

 

Context API에 인스턴스 주입

const calculatorInstance = new Calculator();

const CalculatorContext = createContext(calculatorInstance);

export const CalculatorProvider = ({ children }) => {
  return (
    <CalculatorContext.Provider value={calculatorInstance}>
      {children}
    </CalculatorContext.Provider>
  );
};

 

 

페이지 내에서 활용

import React from 'react';
import { useCalculator } from './CalculatorContext';


export default function Page() {

	const calculator = useCalculator(); // 컨텍스트에서 Calculator 인스턴스를 가져온다.

    const [first , setFirst] = useState(1);
    const [second , setSecond] = useState(2);
    const [result , setResult] = useState(0);

    
    useEffect( () => {
        setResult(calculator.add(1+2));
    } , [first , second])
  
    return(
        <>
                {result}
        </>
    )
}

 

 

 

효과

 

불필요한 재렌더링이 방지되고 해당 인스턴스에 Context 내부에서만 접근이 가능합니다. ( 두 가지 이슈 해결 )

 

리액트가 상태 변경을 추적할 필요가 없어서 관련된 오버헤드가 줄어듭니다.

다만 코드가 조금 길고 신경써야할 Context가 하나 더 추가 되었네요.

 

 

 

4. useState 활용 ( 현재 사용 중 )

 

 

export default function Page() {

	const [calculator] = useState(() => new Calculator());
  
    const [first , setFirst] = useState(1);
    const [second , setSecond] = useState(2);
    const [result , setResult] = useState(0);

    
    useEffect( () => {
        setResult(calculator.add(1+2));
    } , [first , second])
  
	return(
    	<>
            {result}
     	</>
	)
}

 

 

이게 끝입니다.

인스턴스를 State에 주입 시켜주고 사용합니다.

 

 

효과

 

State이기 때문에 직접적인 변경이 없을 시에는 렌더링이 일어나지 않죠. ( 불필요한 재렌더링 방지 )

그리고 상위에서는 접근이 불가능합니다. ( 접근 범위 제한 )

 

하위 컴포넌트에서 접근하고 싶다면 prop으로 내려주면 사용 가능합니다.

여러 곳에서 내려줘야 한다면 코드가 더러워 질 수 있겠습니다.

하지만 저의 경우 많이 내려주지 않아서 관련 이슈는 없었습니다.

 

 


 

 

상황에 맞게 잘 사용하시면 되겠습니다.

 

하나의 인스턴스를 전역적으로 사용하고 싶다면 싱글톤

불필요한 추적 없이 싫거나 클래스를 다양한 하위 컴포넌트에서 사용한다 싶으면 Context

짧은 코드로 깔끔하게 사용하고 싶다면 useState

 

 

 

저는 코드가 짧고 간결하면서 요구 사항을 모두 만족 시킬 수 있어서 useState가 좋았습니다!

 

 

 

 

반응형

'React' 카테고리의 다른 글

[React] useSyncExternalStore 사용 방법과 사용 이유  (6) 2024.03.14
Comments