React 에서 Presentational/Container Component로 관리를 해야한다는 이야기를 듣게 되었습니다.
두개의 컴포넌트는 어떤 컴포넌트를 의미하는지 알고 싶어 예전의 medium글을 읽게 되었습니다.
그리고 이 글을 읽으며 훅의 도입 이유중 하나인 상태로직의 재사용에 대해 이해하게 되었고
컴포넌트는 바보 컴포넌트로 생성을 해야 한다는 생각을 더 강하게 하게 되었습니다.
바보 컴포넌트란 주어진 props를 보여주기만 하는 컴포넌트를 의미합니다.
바보 컴포넌트는 재사용이 쉬워진다는 장점이 있습니다.
글을 살펴보면서 훅은 왜 등장하게 되었고 훅을 주로 사용하는 현재의 시점에서는 저 당시에 존재했던 개념을 어떻게 활용하면 더 좋은 코드를 작성할 수 있을지 알아보려 합니다.
여기서 말하는 더 좋은 코드란 유지보수가 간편하고 재사용성이 뛰어난 코드를 의미합니다.
프로그래밍에서 중요한 개념중 하나는 관심사의 분리입니다.
관심사의 분리란 컴퓨터 프로그램을 구별된 부분으로 분리시키는 디자인 원칙으로, 각 부문은 개개의 관심사를 해결한다
리액트에서는 이를 적용하기 위해 Presentational/Container Component를 도입할 수 있습니다.
Presentational 컴포넌트는 표현하는 역할만 해결하고
Container 컴포넌트는 상태를 관리하는 역할만 해결하는 것입니다.
이 개념을 언급한 Dan Abramov의 글에서는 2019년에 새로운 내용이 글에 추가 됩니다.
더이상 Presentatial/Container 컴포넌트의 사용을 제안하지 않는다는 것입니다.
필요한 경우에 즉 컴포넌트의 재사용성을 필요로 할때 사용해야합니다.
필요하지 않은 경우에도 이와 같은 방식으로 작성되는 것을 많이 보게 되었고 React hook이 그 역할을 대신할 수 있다는 내용입니다.
하지만 저는 훅과 두개의 개념을 같이 사용하면 더 좋은 코드를 작성할 수 있지 않을까 하는 생각을 아래의 출처에 포함된 글을 읽고 생각해보게 되었습니다. 이 글을 빌려 아래의 글을 작성해주신 분께 감사를 표하고 싶네요
기존의 Presentational/Container 방식이 이용된 코드 입니다.
import { useSelector, useDispatch } from 'react-redux'
const TodoContainer = () => {
const todos = useSelector(
// 생략
)
const processTodos = util(todos) // 복잡한 로직
const handleClick = () => {
// 생략
}
return (
<TodoPresentation
todos={processTodos}
onClick={handleClick}
/>
)
}
const TodoPresentation = ({ todos, onClick}) => {
return (
<ul>
{todos && todos.map(({ id, title }) => (
<li key={id}>
{title}
</li>
)
)}
<button type="button" onClick={onClick}>
추가
</button>
</ul>
)
}
Todos의 상태는 TodoContainer Component에서 관리를 합니다.
TodoPresentation Component는 주어진 props를 그려주기만 할뿐 입니다.
TodoPresentation Component는 재사용이 수월하지만 TodoConatiner Component는 재사용을 할 수가 없습니다.
(Presetnation Component를 인자로 받고 관리되는 todos를 넘겨주면 할 수 있을것 같기도 한데 시나리오만 짰는데 벌써 복잡해져 버렸네요)
두개의 관심사는 분리되어 있습니다. Container는 상태의 관리, Presentation은 보여주기만 합니다.
하지만 개선점도 확인되었습니다.
이를 훅을 사용하면 개선할 수 있습니다
아래의 코드는 커스텀 훅으로 작성된 방식입니다.
import { useSelector, useDispatch } from 'react-redux'
const useTodos = () => {
const todos = useSelector(
// 생략
)
const processTodos = util(todos) // 복잡한 로직
const handleClick = () => {
// 생략
}
return {
todos,
onClick: handleClick
}
}
const TodoPresentation = () => {
const { todos, onClick } = useTodos()
return (
<ul>
{todos && todos.map(({ id, title }) => (
<li key={id}>
{title}
</li>
)
)}
<button type="button" onClick={onClick}>
추가
</button>
</ul>
)
}
useTodo 커스텀 훅이 작성되었습다.
이제 상태를 관리하던 로직은 TodoPresentation 에서 사용이 되어집니다.
useTodo 커스텀 훅은 다른 곳에서 재사용이 가능해졌고 독립적인 테스트가 가능해졌습니다.
하지만 TodoPresentation 컴포넌트는 재사용이 불가능 합니다.
상태관련 로직을 컴포넌트 내부에서 불러와서 리스트를 보여주고 추가해주는 역할 외에는 수행할 수 가 없습니다.
Presentational/Container + 커스텀 훅 방식을 이용한 경우입니다.
import { useSelector, useDispatch } from 'react-redux'
import { useSelector, useDispatch } from 'react-redux'
const useTodos = () => {
const todos = useSelector(
// 생략
)
const processTodos = util(todos) // 복잡한 로직
const handleClick = () => {
// 생략
}
return {
todos: processTodos,
onClick: handleClick
}
}
const TodoContainer = () => {
const { todos, onClick } = useTodos()
return (
<TodoPresentation
todos={todos}
onClick={onClick}
/>
)
}
const TodoPresentation = ({ todos, onClick}) => {
return (
<ul>
{todos && todos.map(({ id, title }) => (
<li key={id}>
{title}
</li>
)
)}
<button type="button" onClick={onClick}>
추가
</button>
</ul>
)
}
그래서 합쳐보았습니다.
재사용 가능한 두개를 얻게 되었습니다. 상태관련 로직과 Presentation 컴포넌트는 재사용이 가능해졌습니다.
또한 둘다 독립적인 테스트 또한 시행할 수 가 있습니디ㅏ.
상태관련 로직과 Presentation 컴포넌트는 서로의 관심사가 분리되었고 재사용이 가능합니다.
독립적인 여러 상태관련 로직과 Presentation 컴포넌트를 조합하면 다양한 곳에서 이미 작성되어있는 것들의 재사용이 가능해졌습니다.
React에서 훅의 도입과정중 이해가 되지 않던 부분이 1번 요인인 컴포넌트의 상태관련 로직의 재사용 이었는데
위의 예시와 같이 접하니 이해하기가 더 수월해진것 같습니다!
출처: https://yujonglee.com/socwithhooks.html
https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0
https://ko.wikipedia.org/wiki/%EA%B4%80%EC%8B%AC%EC%82%AC_%EB%B6%84%EB%A6%AC
'Frontend > React' 카테고리의 다른 글
React React-query InfiniteQuery 예제 ∞ (0) | 2022.04.23 |
---|---|
React 글자 4개로 React 컴포넌트 최적화 가능(번역글) 🤔 (0) | 2022.04.20 |
React Redux-saga's work flow from component 🙋♂️ (0) | 2022.04.19 |
React Jsx 🌱 (0) | 2022.04.18 |
React 재조정 🌱 (0) | 2022.04.15 |