저는 보통 FE에서 함수형 적용할 때
계산 로직들은 함수로 따로 생성해두고,
핸들러에서 계산 + 액션을 실행하도록 해요.
이렇게 하는 이유는 액션은 기획이 변경되면 빠르게 수정되어야 하는 로직인데, 계산과 액션이 서로 구별되지 않고 결합이 되어버리면(즉 함수형으로 개발하지 않는다면) 수정해야 하는 범위가 커져버리고, 이 때문에 버그가 발생하는 이슈가 생길 수 있기 때문이에요.
그리고 무엇보다 계산과 액션을 분리하면 가독성이 더 좋아지더라구요.
다음은 함수형으로 작성되지 않은 예시와, 함수형으로 수정했을 때의 예시입니다.
(더 좋은 예시를 들고싶은데 생각이 나지 않네요 ㅠㅠ)
A. 함수형으로 작성하지 않은 코드
// 함수형으로 작성하지 않은 코드
// 액션과 계산이 구별되어 있지 않다.
export function Page() {
const login = async () => {
// 1. 카카오톡 토큰 받기
const result = await post_kakao_oauth_token(code)
// 2. 로그인 요청
const userInfo = await post_oauth_login(result.data.tokens.accessToken)
return userInfo
}
const onClick = async () => {
const userInfo = await login()
// 3. 유저 정보 저장
saveUserInfo({ name: userInfo.name, email: userInfo.email })
}
return (
<div>
<button onClick={onClick}>전송하기</button>
</div>
)
}
B. 함수형으로 작성한 코드
// 함수형으로 작성한 로직
export function Page() {
return (
<div>
<button
onClick={async () => {
// 액션과 계산을 분리하고, 핸들러 안에서 액션을 수행한다. 액션에서 사용되는 계산들도 여기서 실행하여 액션의 매개변수로 넘긴다.
// 1. 카카오톡 토큰 받기 (액션)
const oauthData = await post_kakao_oauth_token(code)
// 2. 필요한 토큰 데이터 추출 (계산)
const accessToken = getToken(oauthData)
// 3. 로그인 요청
const userInfo = await post_oauth_login(accessToken)
// 4. 유저 정보 추출 (계산)
const user = getUserInfo(userInfo)
// 5. 유저 정보 저장 (액션)
saveUserInfo(user)
}}
>
전송하기
</button>
</div>
)
}
// -------- 계산 로직 ------------
const getToken = (oauthData) => {
return oauthData.data.tokens.accessToken
}
const getUserInfo = (userInfo) => {
return {
name: userInfo.name,
email: userInfo.email,
}
}
추가로 onClick, handleClick 이런 식으로 핸들러를 따로 빼내지 않는 이유는
컴포넌트의 핸들러가 어떤 기능을 수행하는지 함수를 대략적으로 쭉 읽었을 때 기능이 파악되었으면 하기 때문입니다.
// 1. 카카오톡 토큰 받기 (액션)
const oauthData = await post_kakao_oauth_token(code)
// 2. 필요한 토큰 데이터 추출 (계산)
const accessToken = getToken(oauthData)
// 3. 로그인 요청
const userInfo = await post_oauth_login(accessToken)
// 4. 유저 정보 추출 (계산)
const user = getUserInfo(userInfo)
// 5. 유저 정보 저장 (액션)
saveUserInfo(user)
적절한 액션/계산 구별을 통해서 핸들러에 함수들을 호출하는 위의 예제(B)를 보시면 수루룩 읽히는 느낌을 받을 수 있을것입니다.
하지만 onClick로 핸들러를 따로 선언하고 전달하게 되면 하나의 기능을 하는 컴포넌트와 핸들러 사이의 물리적(코드적?)거리가 생기므로
코드상을 왔다갔다 하면서 읽을 수 밖에 없어지고 이는 가독성이 떨어지게 하는 요인이라고 생각해요.
그리고 대부분 코드를 작성하다 보면 onClick함수를 여러 개의 다른 컴포넌트에게 전달하는 경우는 거의 없더라구요.
있더라도 2번 정도는 반복해서 작성해도 문제가 없으며, 기획이 변경되어 두 컴포넌트의 기능이 갈라지는 경우가 생기면 오히려 의존성이 높아지기도 합니다.
저는 보통 FE에서 함수형 적용할 때 계산 로직들은 함수로 따로 생성해두고, 핸들러에서 계산 + 액션을 실행하도록 해요.
이렇게 하는 이유는 액션은 기획이 변경되면 빠르게 수정되어야 하는 로직인데, 계산과 액션이 서로 구별되지 않고 결합이 되어버리면(즉 함수형으로 개발하지 않는다면) 수정해야 하는 범위가 커져버리고, 이 때문에 버그가 발생하는 이슈가 생길 수 있기 때문이에요.
그리고 무엇보다 계산과 액션을 분리하면 가독성이 더 좋아지더라구요.
다음은 함수형으로 작성되지 않은 예시와, 함수형으로 수정했을 때의 예시입니다. (더 좋은 예시를 들고싶은데 생각이 나지 않네요 ㅠㅠ)
A. 함수형으로 작성하지 않은 코드
B. 함수형으로 작성한 코드
추가로
onClick
,handleClick
이런 식으로 핸들러를 따로 빼내지 않는 이유는 컴포넌트의 핸들러가 어떤 기능을 수행하는지 함수를 대략적으로 쭉 읽었을 때 기능이 파악되었으면 하기 때문입니다.적절한 액션/계산 구별을 통해서 핸들러에 함수들을 호출하는 위의 예제(B)를 보시면 수루룩 읽히는 느낌을 받을 수 있을것입니다.
하지만
onClick
로 핸들러를 따로 선언하고 전달하게 되면 하나의 기능을 하는 컴포넌트와 핸들러 사이의 물리적(코드적?)거리가 생기므로 코드상을 왔다갔다 하면서 읽을 수 밖에 없어지고 이는 가독성이 떨어지게 하는 요인이라고 생각해요. 그리고 대부분 코드를 작성하다 보면onClick
함수를 여러 개의 다른 컴포넌트에게 전달하는 경우는 거의 없더라구요. 있더라도 2번 정도는 반복해서 작성해도 문제가 없으며, 기획이 변경되어 두 컴포넌트의 기능이 갈라지는 경우가 생기면 오히려 의존성이 높아지기도 합니다.