네임스페이스 패턴이란 관련있는 코드의 조각들을 하나의 논리적 집합으로 그룹화하는 것을 뜻한다. 이를 통해 코드의 가독성을 높이고, 유지보수가 용이해지는 장점이 있다. 네임 스페이스 패턴은 주로 C++과 같은 객체지향 프로그래밍에서 사용하는 패턴이지만, 함수형 프로그래밍인 리액트에서도 유용하게 사용할 수 있다.
React에서의 네임스페이스 패턴(namespace pattern)은 구성 요소들 간의 명확한 구조를 제공하고, 유지보수성을 높이며, 재사용 가능한 코드를 작성할 때 사용하는 일종의 디자인 패턴이다. 이 패턴은 규모가 크거나, 커스텀해야하는 기능들이 있을 때 특히 유용하다. 또한 각 구성 요소의 역할을 명확히 하고, 개발의 자동화를 돕는다.
react에서 form
컴포넌트를 제작한다고 가정해보자. 이 form
컴포넌트에는 label
, input
, button
등의 다양한 서브 컴포넌트들이 필요할 수 있다. 이때 각각 따로따로 만드는 것이 아닌, form
에서 사용하는 컴포넌트라는 공통된 특징을 바탕으로 네임스페이스를 설정하여 컴포넌트들을 관리할 수 있다.
// Form 네임스페이스 정의
import React, { FC, FormEvent, ChangeEvent } from 'react';
interface FormProps {
children: React.ReactNode;
onSubmit: (e: FormEvent<HTMLFormElement>) => void;
}
const Form: FC<FormProps> & {
Input: FC<InputProps>;
Label: FC<LabelProps>;
Button: FC<ButtonProps>;
} = ({ children, onSubmit }) => (
<form onSubmit={onSubmit}>
{children}
</form>
);
interface InputProps {
type: string;
name: string;
placeholder?: string;
value: string;
onChange: (e: ChangeEvent<HTMLInputElement>) => void;
}
Form.Input = ({ type, name, placeholder, value, onChange }: InputProps) => (
<input type={type} name={name} placeholder={placeholder || ''} value={value} onChange={onChange} />
);
interface LabelProps {
htmlFor: string;
children: React.ReactNode;
}
Form.Label = ({ htmlFor, children }: LabelProps) => (
<label htmlFor={htmlFor}>{children}</label>
);
interface ButtonProps {
type: "button" | "submit" | "reset";
onClick?: () => void;
children: React.ReactNode;
}
Form.Button = ({ type, onClick, children }: ButtonProps) => (
<button type={type} onClick={onClick}>{children}</button>
);
// Form 컴포넌트 사용 예시
const SignupForm: FC = () => {
const [formData, setFormData] = React.useState({ username: '', password: '' });
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target;
setFormData(prev => ({ ...prev, [name]: value }));
};
const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
console.log('Form Data Submitted:', formData);
};
return (
<Form onSubmit={handleSubmit}>
<Form.Label htmlFor="username">Username:</Form.Label>
<Form.Input
type="text"
name="username"
placeholder="Enter your username"
value={formData.username}
onChange={handleChange}
/>
<Form.Label htmlFor="password">Password:</Form.Label>
<Form.Input
type="password"
name="password"
placeholder="Enter your password"
value={formData.password}
onChange={handleChange}
/>
<Form.Button type="submit">Submit</Form.Button>
</Form>
);
}
관련 기능이 같은 네임스페이스에 포함되어 있어 수정이 필요할 때 찾기 쉽고, 변경 사항이 다른 부분에 미치는 영향을 최소화할 수 있다.
사실 react에서 네임스페이스 패턴을 사용하는 가장 큰 이유라고 볼 수 있다. 하나의 프로젝트에서는 수많은 button
컴포넌트들이 필요할 수 있는데, 이때 네임스페이스화 해놓은 특정한 button
컴포넌트를 사용하면 뚜렷하게 구분할 수 있다.
네임스페이스 패턴을 처음 설정할 때는 구조를 설계하는 데 시간과 노력이 필요할 수 있다.
네임스페이스를 너무 세밀하게 나누면 오히려 관리가 복잡해질 수 있으며, 코드의 양이 불필요하게 많아질 수 있다. 때문에 사전에 팀원과 적절한 룰을 설정해야한다.