헤드리스 컴포넌트 디자인 패턴은 무엇일까
헤드리스 컴포넌트를 한 줄로 요약하면 다음과 같다.
로직과 스타일을 분리하여 높은 유연성과 재사용성을 제공하는 디자인 패턴
이 디자인 패턴은 UI와 관련된 로직을 독립적으로 관리할 수 있게 하여, 다양한 프로젝트에서 동일한 로직을 사용하면서도 다른 스타일을 적용할 수 있도록 한다. 이를 통해 코드의 재사용성과 유지보수성을 높이며, 개발자는 로직 업데이트 시 스타일을 변경할 필요 없이 작업할 수 있다.
// useDropdown.js (헤드리스 컴포넌트)
import { useState } from 'react';
export const useDropdown = (options) => {
const [isOpen, setIsOpen] = useState(false);
const [selectedOption, setSelectedOption] = useState(null);
const toggleDropdown = () => setIsOpen(!isOpen);
const selectOption = (option) => {
setSelectedOption(option);
setIsOpen(false);
};
return {
isOpen,
selectedOption,
toggleDropdown,
selectOption,
options,
};
};
// Dropdown.js (프레젠테이션 컴포넌트)
import React from 'react';
import { useDropdown } from './useDropdown';
const Dropdown = ({ options }) => {
const { isOpen, selectedOption, toggleDropdown, selectOption } = useDropdown(options);
return (
<div className="dropdown">
<button onClick={toggleDropdown}>
{selectedOption ? selectedOption.label : '옵션을 선택하세요'}
</button>
{isOpen && (
<ul>
{options.map((option) => (
<li key={option.value} onClick={() => selectOption(option)}>
{option.label}
</li>
))}
</ul>
)}
</div>
);
};
export default Dropdown;
// useForm.js (헤드리스 컴포넌트)
import { useState } from 'react';
export const useForm = (initialValues) => {
const [values, setValues] = useState(initialValues);
const handleChange = (e) => {
const { name, value } = e.target;
setValues({
...values,
[name]: value,
});
};
const handleSubmit = (callback) => (e) => {
e.preventDefault();
callback(values);
};
return {
values,
handleChange,
handleSubmit,
};
};
// Form.js (프레젠테이션 컴포넌트)
import React from 'react';
import { useForm } from './useForm';
const Form = ({ initialValues, onSubmit }) => {
const { values, handleChange, handleSubmit } = useForm(initialValues);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input
type="text"
name="username"
value={values.username}
onChange={handleChange}
placeholder="사용자 이름"
/>
<input
type="password"
name="password"
value={values.password}
onChange={handleChange}
placeholder="비밀번호"
/>
<button type="submit">제출</button>
</form>
);
};
export default Form;
헤드리스 컴포넌트는 스타일이나 레이아웃에 종속되지 않고 순수하게 기능에 집중하는 컴포넌트다. 다음은 헤드리스 컴포넌트를 고려해야 하는 주요 이유다:
https://headlessui.com/
재사용성을 극대화했기에, 공용으로 쓰이는 컴포넌트는 위 페이지에서처럼 개발자들간 공유도 자유롭게 한다.
// 프레젠테이셔널 컴포넌트
const Button = ({ onClick, children }) => (
<button onClick={onClick} className="btn-primary">
{children}
</button>
);
// 컨테이너 컴포넌트
class ButtonContainer extends React.Component {
handleClick = () => {
console.log("Button clicked");
};
render() {
return <Button onClick={this.handleClick}>Click Me</Button>;
}
}