DRAFT
가상의 게시판을 만든다고 가정해 보겠습니다.
const ArticleBoardPage = () => {
const [user, setUser] = useState();
const [articles, setArticles] = useState();
const page = window.location.query.page;
useEffect(() => {
setUser(await fetchUser());
setArticles(await fetchArticles(page));
}, []);
return (
<div>
<div>
{user.name}님 안녕하세요<br/>
작성 글: {user.articles.length}개
</div>
<div>
{articles.map(article => (
<div>
{article.title} - {article.author}
</div>
)}
<button onClick={() => window.location.href='/write'}>
글쓰기
</button>
</div>
</div>
);
}
위 코드는 간단하게 작성할 수 있는 못 짠 게시판 코드이며, 전혀 함수형스럽지 않습니다.
왜 함수형스럽지 않을까요?
만약 위 코드가 아래와 같이 되면 어떨까요?
const ArticleBoardPage = () => {
return (
<div>
<UserProfile />
<ArticleList
page={window.location.query.page}
/>
</div>
);
};
단순히 코드를 묶어서 컴포넌트화 했다고 생각하시나요?
각 컴포넌트를 한번씩 살펴보도록 하겠습니다.
<UserProfile userId={myUserId} />
map
도 내부적으론 i
라는 상태를 가지겠죠?)<ArticleList page={1} />
const BigHugeMonolithApp = () => ProfilePage
| LoginPage
| SignUpPage
| SettingPage
| ArticlePage;
const TinyArticleComponent = () => Article;
const TinyArticleComponent = () => Article
| LoadingComponent
| ErrorRetryComponent;
(아무리 잘 짜도 App은 결국 위 코드처럼 될 수밖에 없습니다. 그냥 monolith식 컴포넌트를 만들수록 '함수형'의 컨셉이 망가진다고 생각해주세요.)
// 이 컴포넌트는 화면의 맨 위에 네모를 출력합니다.
// 일반적인 다이얼로그/모달 컴포넌트입니다.
<Dialog />
// 이 컴포넌트는 유저 정보를 출력합니다.
<UserProfile />
// 이제 화면의 맨 위에 표시되는 모달 안에
// 유저 정보가 출력됩니다.
<Dialog>
<UserProfile />
</Dialog>
눈치채셨나요?
컴포넌트를 잘게 쪼개서 함수 에 가깝게 만들수록 재사용성(가지고 놀 수 있는 범위)가 늘어납니다.
훅 또한 그 자체로 함수이며, 합성의 대상이 될 수 있습니다.
// 게시물 목록을 가져옵니다.
useArticles();
// 내가 숨김처리 설정한 키워드 목록을 가져옵니다.
useBannedKeywords();
// 내가 숨김처리 설정한 키워드가 포함되지 않은
// 게시물 목록을 가져옵니다.
const useRefinedArticles = () => {
const articles = useArticles();
const bannedKeywords = useBannedKeywords();
return articles
.filter(x => !bannedKeywords.some(y => x.body.includes(y));
};