티스토리 뷰
코딩을 하면서 놓치고 갈 수 없는 부분 중 하나가 바로 '재사용성'이다. 재사용성을 높이면 반복되는 코드를 줄일 수 있을 뿐만 아니라 확장성까지 높일 수 있어 추후에 작업을 해나갈 때 매우 편리하다. 이번 프로젝트를 하면서 재사용 가능한 컴포넌트 단위를 만들어서 사용 해보는데, 한 번은 그대로 재사용하였고, 한 번은 컴포넌트를 확장하여 사용하였다. 각각 어떻게 사용했는지 이 글에 적어 놓고자 한다. 여기서는 React, TypeScript, Styled-Components를 사용하였다.
✅ 1. 컴포넌트 재사용하기
위의 네 가지 버튼을 언뜻 보면 배경색이나 내부 컨텐츠가 매우 다르게 생겼다. 배경 색도 제각각이고, 내부 컨텐츠에도 어떤 것은 text만 들어있고, 어떤 것은 text와 image 도 함께 들어있고 심지어 어떤 것은 input이 들어있기도 하다.
하지만 동일한 외형과 같은 크기의 padding을 가지고 있다. 그리고 click했을 때 특정한 event를 발생시킬 수도 있다. 내부 content는 결국 버튼의 children에 무엇을 넣느냐에 따라 다를 뿐이다.
한 번 재사용 가능한 컴포넌트를 만들어 두면 쉽게 import 하여 사용할 수 있고, 공통적인 수정사항이 생겼을 때 빠르게 적용할 수도 있으므로 이 편이 더 편리하다고 할 수 있다.
🔥 CommomButton
import React from 'react';
import { ReactNode } from 'react';
import styled from 'styled-components';
type ButtonProps = {
className: string;
onClick?: () => void;
children?: ReactNode;
};
const CommonButton = ({ className, onClick, children }: ButtonProps) => {
return (
<ButtonWrapper className={className} onClick={onClick}>
{children}
</ButtonWrapper>
);
};
export default CommonButton;
const ButtonWrapper = styled.button`
display: flex;
outline: none;
align-items: center;
border-radius: 20px;
`;
공통 속성을 공유하는 컴포넌트를 CommonButton이라는 이름으로 만들었다. onClick 이벤트와 Children을 props로 받는다. className은 styled-components에서 'styled()' 문법을 사용하여 확장할 때 className이 있어야 하기 때문에 넣어주어야 한다. 그리고 공통적인 styling을 해주었다.
🔥 CommonButtom을 재사용하여 만든 더보기 버튼(ToggleIntroButton)
import React, { useState } from 'react';
import styled from 'styled-components';
type MoreIntro = {
moreIntro: boolean;
};
const BookInfo = () => {
const [moreIntro, setMoreIntro] = useState(false);
const toggleIntro = () => {
moreIntro ? setMoreIntro(false) : setMoreIntro(true);
};
return (
<BookInfoWrapper>
<ToggleIntroButton className="moreIntroButton" onClick={toggleIntro}>
{moreIntro ? '숨기기' : '더보기'}{' '}
</ToggleIntroButton>
</BookInfoWrapper>
);
};
export default BookInfo;
const BookInfoWrapper = styled.section`
padding-bottom: 40px;
border-bottom: 1px solid ${(props) => props.theme.colors.grey4};
`;
const ToggleIntroButton = styled(CommonButton)`
display: block;
box-sizing: border-box;
width: 112px;
height: 44px;
margin: 12px auto 0;
padding: 12px 16px;
color: ${(props) => props.theme.colors.black};
font-size: ${(props) => props.theme.fontSize.body02};
font-weight: ${(props) => props.theme.fontWeight.regular};
line-height: ${(props) => props.theme.lineHeight.lh20};
background-color: ${(props) => props.theme.colors.white};
border: 1px solid ${(props) => props.theme.colors.grey3};
font-family: inherit;
border-radius: 24px;
outline: none;
`;
✅ 2. 컴포넌트 확장하여 재사용하기
댓글과 대댓글을 작성할 수 있는 컴포넌트이다. 둘은 공통적으로 댓글 입력을 받는 부분과 등록 버튼이 존재한다. 하지만 댓글을 작성하는 input 컴포넌트에는 페이지를 입력할 수 있는 다른 input 요소가 존재한다는 점이 다르다. 그래서 대댓글 컴포넌트를 재사용 가능한 단위로 만들고, 댓글 컴포넌트에서는 이를 확장하여 사용해 보았다.
🔥 대댓글 컴포넌트(InputComment)
import React, { ReactNode } from 'react';
import styled from 'styled-components';
import CommonButton from '../../../components/CommonButton';
type InputProps = {
className: string;
placeholder: string;
onClick: () => void;
children?: ReactNode;
};
const InputComment = ({ className, placeholder, onClick, children }: InputProps) => {
return (
<InputWrapper className={className}>
{children}
<InputArea placeholder={placeholder} />
<InputButtonWrapper>
<InputButton className={className} onClick={onClick}>
댓글등록
</InputButton>
</InputButtonWrapper>
</InputWrapper>
);
};
export default InputComment;
const InputWrapper = styled.div`
display: flex;
width: 100%;
min-height: 110px;
padding: 20px;
border: 1px solid ${(props) => props.theme.colors.grey4};
border-radius: 8px;
position: relative;
box-sizing: border-box;
`;
const InputArea = styled.textarea`
flex: 1;
display: block;
min-height: 70px;
resize: none;
outline: none;
border: none;
overflow-y: visible;
`;
const InputButtonWrapper = styled.div`
width: 100px;
`;
const InputButton = styled(CommonButton)`
position: absolute;
right: 20px;
bottom: 20px;
padding: 12px 16px;
background-color: ${(props) => props.theme.colors.primary};
border: none;
font-size: ${(props) => props.theme.fontSize.body02};
font-weight: ${(props) => props.theme.fontWeight.bold};
`;
textarea로 여러줄 입력(글 입력)을 받을 것인데, 이 textarea 좌측에 children이 올 수 있도록 하였다.
InputButton은 위에서 만든 CommonButton을 재사용하고, styling을 확장하여 사용하였다.
🔥 댓글 컴포넌트 (InputCommentWithPag)
import React from 'react';
import styled from 'styled-components';
import InputComment from './InputComment';
import CommonButton from '../../../components/CommonButton';
type InputCommentProps = {
className: string;
onClick: () => void;
placeholder: string;
};
const InputCommentWithPage = ({ className, onClick, placeholder }: InputCommentProps) => {
return (
<InputCommentWrapper className={className} placeholder={placeholder} onClick={onClick}>
<InputPageWrapper>
<span>책 페이지</span>
<InputPage className="pageInput">
<input placeholder="숫자 입력" />
p.
</InputPage>
</InputPageWrapper>
</InputCommentWrapper>
);
};
export default InputCommentWithPage;
const InputCommentWrapper = styled(InputComment)`
display: flex;
`;
const InputPageWrapper = styled.div`
display: flex;
flex-direction: column;
justify-content: space-between;
padding-right: 20px;
margin-right: 20px;
border-right: 1px solid ${(props) => props.theme.colors.grey4};
> span {
font-size: ${(props) => props.theme.fontSize.body02};
font-weight: ${(props) => props.theme.fontWeight.bold};
}
`;
const InputPage = styled(CommonButton)`
padding: 12px 16px;
border: 1px solid ${(props) => props.theme.colors.grey4};
background-color: ${(props) => props.theme.colors.white};
color: ${(props) => props.theme.colors.grey1};
> input {
width: 66px;
border: none;
outline: none;
&::placeholder {
font-family: inherit;
font-size: ${(props) => props.theme.fontSize.badge01};
font-weight: ${(props) => props.theme.fontWeight.bold};
color: ${(props) => props.theme.colors.grey1};
}
}
`;
위에서 만든 InputComment(여기서는 추가적인 styling을 하기 위해서 InputCommnetWrapper라고 사용하였다.) 안에 추가할 요소(InputPageWrapper)만 넣어주면 위와 같은 댓글 컴포넌트를 만들 수 있다. 반복하여 작성해야 했던 코드를 매우 줄일 수 있다.
💡 예전엔 React, TypeScript, Styled-Components 문법에 익숙하지 않아 재사용 컴포넌트를 만들어 사용하고 싶어도 그러지 못했다. 사용에 조금 익숙해진 지금, 어떻게 하면 재사용 컴포넌트를 만들어서 사용할 수 있을까 고민하고 도전하여 만들어 보았다. 그래서 아직 미숙한 점이 있을 수 있다.
댓글 및 피드백은 언제나 감사합니다.
'프로젝트' 카테고리의 다른 글
[React] custom hook으로 이미지 저장 로직 개선하기 (0) | 2023.11.16 |
---|---|
React 프로젝트 폴더구조 리팩토링 (1) | 2023.10.16 |
[Styled-components] 슬라이드 토글 버튼 만들기 (0) | 2022.10.26 |
[출판] 손으로 익히는 자바스크립트 기초 (0) | 2022.01.01 |