어쩌면 유일하게(?) 알고 있는 패턴...!
부트캠프에서 Container/Presentational 패턴을 기본적으로 가르쳐서 부트캠프 플젝은 다 이 패턴으로 구현되어 있다.
이 블로그를 작성하며 공부하다 보니 Hooks 형태로 react를 배웠는데 왜 굳이 이 패턴을 기본으로 가르쳐준건지 의아함이 생겼다.
React에서 관심사의 분리(SoC)를 강제하는 방법은 Container/Presentational Pattern을 이용하는 방법이 있다.
이를 통해 비즈니스 로직에서 뷰를 분리해낼 수 있다.
6개의 강아지 사진을 다운로드 받아 화면에 렌더하는 앱을 만든다고 가정해보자.
이상적으로는 이 프로세스를 두 가지로 분리하여 관심사의 분리를 강제하고 싶다.
강아지 사진을 다운로드 하는 것이 비즈니스 로직의 역할이고, 이미지를 보여주는 것은 뷰의 역할이다.
Presentational 컴포넌트는 props를 통해 데이터를 받는다. 이 컴포넌트의 주요 기능은 받은 데이터를 화면에 표현하는 것이며 그 목적을 위해 스타일 시트를 포함한다.
import React from "react";
export default function DogImages({dogs}) {
return dogs.map((dog, i) => <img src={dog} key={i} alt="Dog" />);
}
여기서 DogImages
컴포넌트는 Presentational 컴포넌트이다. Presentational 컴포넌트는 UI 변경을 위한 상태 외에는 상태를 갖지 않는다.
prop을 통해 받은 데이터는 Presentational 컴포넌트에 의해 수정되지 않는다. Presentational 컴포넌트는 Container 컴포넌트로부터 데이터를 받는다.
Container 컴포넌트의 주요 기능은 Presentational 컴포넌트에 데이터를 전달하는 것이다. Container 컴포넌트 자체는 화면에 아무것도 렌더링하지 않는다. Container 컴포넌트는 아무것도 화면에 그리지 않기 때문에 스타일 시트도 포함하지 않는다.
import React from "react";
import DogImages from "./DogImages";
export default class DogImagesContainer extends React.Component {
constructor() {
super();
this.state = {
dogs: []
};
}
componentDidMount() {
fetch("https://dog.ceo/api/breed/labrador/images/random/6")
.then(res => res.json())
.then(({ message }) => this.setState({ dogs: message }));
}
render() {
return <DogImages dogs={this.state.dogs} />;
}
}
대개 Container/Presentational 패턴은 React Hooks로 대체 가능하다. React에 Hooks가 추가되면서 Container 컴포넌트 없이도 stateless 컴포넌트를 쉽게 만들 수 있게 되었다.
DogImagesContainer
컴포넌트에 있는 데이터 로드 코드를 아래와 같이 커스텀 훅으로 만들 수 있다.
export default function useDogImages() {
const [dogs, setDogs] = useState([])
useEffect(() => {
fetch('https://dog.ceo/api/breed/labrador/images/random/6')
.then(res => res.json())
.then(({ message }) => setDogs(message))
}, [])
return dogs
}
이 훅을 사용하면 데이터를 받아오기 위해 DogImagesContainer
컴포넌트를 사용할 필요가 없다. 대신 Presentational 컴포넌트인 DogImages
에서 훅을 직접 호출해 사용하면 된다.
import React from "react";
import useDogImages from "./useDogImages";
export default function DogImages() {
const dogs = useDogImages();
return dogs.map((dog, i) => <img src={dog} key={i} alt="Dog" />);
}
Hooks는 Container/Presentational 패턴처럼 비즈니스 로직과 뷰를 쉽게 분리할 수 있게 해주고, 불필요한 Container 랩핑을 줄일 수 있게 해준다.
< 출처 : https://patterns-dev-kr.github.io/design-patterns/container-presentational-pattern/ >