의존성 주입(dependency injection) : 어떤 함수나 클래스가 자신들이 내부적으로 사용할 기능을 자신들 내부에서(즉 스스로가) 만들어내지 않고, 외부에서 이 기능들을 만든 뒤 주입시키는 것.

 

예를 들어, app.jsx에서 유튜브 api를 호출하는 기능을 쓴다고 할 때 이 기능을 app.jsx 내에서 만들 수도 있겠지만, 외부에서 유튜브 api를 호출하는 기능을 만든 다음 app.jsx에게 주입(by props)하여 이를 쓰게 할 수도 있다. 이를 의존성 주입이라 한다. 찾아보니까 객체 지향 프로그래밍(OOP)에서 코드의 재사용성을 목적으로 잘 사용되는 패턴이라고 한다.  (MVC패턴 등에서 view에 해당하는 애들이 비즈니스 로직도 처리할 수 있고 ~~도 할 수 있고~ 그러면 곤란..) 리액트에서는 컴포넌트들의 테스트를 하는 것에도 DI를 쓰는 게 좋다고 한다. 

 

리액트에선 index.js에서 사용할 함수 등을 불러와 app.jsx에 집어넣고, 그 다음은 이를 쓰는 컴포넌트로 계속해서 전달전달하는 식으로 활용한다. 예를 들면 다음과 같다.

const authService = new AuthService();

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App authService={authService}/> 
  </React.StrictMode>
);

// authService객체는 login등의 메소드를 사용가능한 객체이다

그러면, App컴포넌트 안에 B컴포넌트 안에 C컴포넌트 안에 D컴포넌트 안에 E컴포넌트가 있다고 해보자. 또한 E컴포넌트는 login과 logout이라는 기능을 써야 한다. 이 때 방금 한 것처럼 index.js에서 login, logout메소드를 쓸 수 있는 객체(authService라고 가정)를 만들어 app.jsx에 넣어주고, app이 이를 계속 전달전달해주는 방식을 쓸 수 있다. 

// index.js

const authService = new AuthService();

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App authService={authService}/> 
  </React.StrictMode>
);


// app.jsx

function App({authService}){
	return <B authService={authService} />;
}


// B .jsx

function B({authService}){
	return <C authService={authService} />;
}


// C.jsx

function C({authService}){
	return <D authService={authService} />;
}


// D.jsx

function D({authService}){
	return <E authService={authService} />;
}


// E.jsx

function E({authService}){
	return(
    	<>
           <button onClick={authService.login}>로그인</button>
           <button onClick={authService.logout}>로그아웃</button>
        </>
    );
}

이 때 E에서 다른 기능들도 이용해야 한다면? 그래서 index.js에서 다른 객체를 만들어 E에 전달해야 한다면? app.jsx, B.jsx, C.jsx, D.jsx에 하나하나 직접 코딩을 해줘야 한다. 이 작업? 너무 귀찮다.

 

그래서 여기서 꼼수(?)가 하나 있다. index.js에서 애시당초에 필요한 의존성들을 집어넣은 E라는 컴포넌트를 만들어 이걸 전달하는 것이다. 다음과 같다.

const authService = new AuthService();
const youtube = new Youtube();

const Jofe = props => {
  return(
    <E {...props} authService={authService} youtube={Youtube}/>
  );
};

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App Jofe={Jofe}/> 
  </React.StrictMode>
);

return <E authService={authService} youtube={youtube} /> 를 해도 되지만 확장성을 위해 저렇게 한 번 감싼 형태의 컴포넌트로 만들어서 전달할 수도 있다. 이렇게 하면 장점은, E에 새로 전달할 객체가 있어도 index.js에서 한 번만 수정하면 된다. 

+ Recent posts