<aside> <img src="/icons/search_gray.svg" alt="/icons/search_gray.svg" width="40px" />
설명 참고 및 코드 출처 JavaScript in Plain English
</aside>
user
상태는 name
, surname
, address
3개 속성을 가지며, 이에 대응하는 3개의 input 필드가 필요하다. 아래 코드에선 각 필드를 처리하기 위해 별도의 핸들러를 각각 만들어서 사용하고 있지만, 이 핸들러들은 value가 할달될 속성 이름만 다를 뿐 나머지 로직이 동일하기 때문에 코드 중복이 발생하고 있다.
export default function App() {
const [user, setUser] = useState({
name: "",
surname: "",
address: ""
});
const handleNameChange = (e) => {
setUser((prev) => ({
...prev,
name: e.target.value
}));
};
const handleSurnameChange = (e) => {
setUser((prev) => ({
...prev,
surname: e.target.value
}));
};
const handleAddressChange = (e) => {
setUser((prev) => ({
...prev,
address: e.target.value
}));
};
return (
<>
<input value={user.name} onChange={handleNameChange} />
<input value={user.surname} onChange={handleSurnameChange} />
<input value={user.address} onChange={handleAddressChange} />
</>
);
}
함수형 프로그래밍에서 자주 사용하는 커링은 n개의 인자를 받는 대신 n개의 함수를 만들어서 하나의 인자만 받도록 만드는 패턴이다.
currying is the technique of translating a function that takes multiple arguments into a sequence of families of functions, each taking a single argument.
커링 패턴을 적용하여 기존 이벤트 핸들러를 각 속성에 대응하는 함수를 반환하도록 만들면, 특정 필드에 맞는 핸들러를 동적으로 생성할 수 있어 중복 코드를 줄일 수 있다.
export default function App() {
const [user, setUser] = useState({
name: "",
surname: "",
address: ""
});
const handleInputChange = (field) => {
// 반환될 핸들러
return (e) => {
setUser((prev) => ({
...prev,
[field]: e.target.value
}));
};
};
return (
<>
<input value={user.name} onChange={handleInputChange("name")} />
<input value={user.surname} onChange={handleInputChange("surname")} />
<input value={user.address} onChange={handleInputChange("address")} />
{JSON.stringify(user)}
</>
);
}
1개 컴포넌트에 너무 많은 코드 라인을 포함하면 유지보수하기 힘들고 이해하기도 쉽지 않다. 이러한 컴포넌트는 아래와 같은 기준을 가지고 독립적인 하위 모듈로 분리하는 것이 좋다.