리액트에서 가장 유명한 패턴인이자 가독성과 생산성을 고려한 방법인 프레젠테이션 컴포넌트
와 컨테이너 컴포넌트
에 대해 알아보려고 한다.
화면을 표현하는 부분
(Presentational Components)와 데이터를 다루는 부분
(Container Components)으로 나눠서 개발하는 패턴으로 재사용성과 유지보수의 장점이 있다.
My presentational components:
Are concerned with how things look.
May contain both presentational and container components** inside, and usually have some DOM markup and styles of their own.
Often allow containment via this.props.children.
Have no dependencies on the rest of the app, such as Flux actions or stores.
Don’t specify how the data is loaded or mutated.
Receive data and callbacks exclusively via props.
Rarely have their own state (when they do, it’s UI state rather than data).
Are written as functional components unless they need state, lifecycle hooks, or performance optimizations.
Examples: Page, Sidebar, Story, UserInfo, List.
My container components:
Are concerned with how things work.
May contain both presentational and container components** inside but usually don’t have any DOM markup of their own except for some wrapping divs, and never have any styles.
Provide the data and behavior to presentational or other container components.
Call Flux actions and provide these as callbacks to the presentational components.
Are often stateful, as they tend to serve as data sources.
Are usually generated using higher order components such as connect() from React Redux, createContainer() from Relay, or Container.create() from Flux Utils, rather than written by hand.
Examples: UserPage, FollowersSidebar, StoryContainer, FollowedUserList.
출 처 : 댄 아브라모프(Dan Abramov) 블로그
https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0
📗 예제를 통해 알아보자.
App 컴포넌트 👈 이런게 바로 프레젠테이션 컴포넌트다!
import React from 'react';
import InputContainer from './InputContainer';
export default function App() {
return (
<InputContainer />
);
}
InputContainer 컴포넌트 👈 이런게 바로 컨테이너 컴포넌트다!
import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import Input from './Input';
import {
updateTaskTitle,
addTask,
} from './actions';
export default function InputContainer() {
const { taskTitle } = useSelector((state) => ({
taskTitle: state.taskTitle,
}));
const dispatch = useDispatch();
function handleChangeTitle(event) {
dispatch(updateTaskTitle(event.target.value));
}
function handleClickAddTask() {
dispatch(addTask());
}
return (
<Input
value={taskTitle}
onChange={handleChangeTitle}
onClick={handleClickAddTask}
/>
);
}
✏️ 새겨두기
"되도록 컴포넌트를 작성하는 입장에서는 유지 보수하기 쉬운 코드를, 컴포넌트를 사용하는 사람 입장에서는 컴포넌트의 인터페이스를 쉽게 파악할 수 있는 코드를 작성하는게 좋다."
참고 문서: 실전 리액트 프로그래밍 [이재승 지음, 인사이트]