Flutter에서 Hooks는 UI 로직을 관리하는 새로운 방식으로, 기존의 StatefulWidget을 대체하거나 보완하여 코드의 가독성을 높이고 로직을 간결하게 만들어준다. React에서 처음 도입된 Hooks는 Flutter에서도 비슷한 개념으로 사용되며, 특히 반복적인 초기화 및 해제 작업을 줄이고 재사용성을 높이는 데 유용하다.
(단, React Hooks 처럼 공식 지원이 아니고 flutter_hooks 라는 서드파티 패키지 설치를 통해 사용이 가능하다.)
Hooks란 무엇인가?
1. React에서의 Hooks
- 클래스 없이 상태를 관리할 수 있도록 도와주는 기능
- https://honken.tistory.com/140 (예전 React Hooks 정리글)
2. Flutter에서의 Hooks
- HookWidget을 사용하여 여러 개의 Hook을 한 위젯에 연결 가능
- 각 Hook은 자체적으로 초기화 및 해제를 처리하므로, 개발자가 직접 initState()나 dispose()를 작성할 필요가 없음
- 코드의 가독성을 높이고 중복을 줄이며, 특히 대규모 프로젝트에서 유용
아래의 예제 코드로 더 자세히 알아보자.
1. 기존 StatefulWidget 방식
class Home extends StatefulWidget {
@override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> with SingleTickerProviderStateMixin {
AnimationController animationController;
@override
void initState() {
super.initState();
animationController = AnimationController(
vsync: this,
duration: Duration(milliseconds: 1000),
value: 1,
)..addListener(() {
if (animationController.status == AnimationStatus.completed) {
animationController.repeat();
}
setState(() {});
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: GestureDetector(
onTap: animationController.forward,
onDoubleTap: animationController.reverse,
child: FadeTransition(
opacity: animationController,
child: Center(child: FlutterLogo(size: 300)),
),
),
);
}
@override
void dispose() {
animationController.dispose();
super.dispose();
}
}
- initState()와 dispose()에서 AnimationController를 초기화하고 해제해야 함
- 코드가 복잡해지고, 특히 여러 화면에서 동일한 로직을 반복해야 할 경우 유지보수가 어려움
2. HookWidget 방식
class Home extends HookWidget {
@override
Widget build(BuildContext context) {
final hookAnimation = useAnimationController(
duration: Duration(milliseconds: 1000),
initialValue: 1,
);
return Scaffold(
body: GestureDetector(
onTap: () => hookAnimation.forward(),
onDoubleTap: () => hookAnimation.reverse(),
child: FadeTransition(
opacity: hookAnimation,
child: Center(child: FlutterLogo(size: 300)),
),
),
);
}
}
- useAnimationController()를 사용하여 간단히 AnimationController 생성.
- initState()와 dispose()가 필요없음
- 전자에 비해 훨씬 간결하고 가독성이 높아진 코드
Custom Hook 만들기
여러 화면에서 동일한 스크롤과 애니메이션 로직이 필요하다면 이를 매번 작성하는 것은 비효율적일 것이다. 따라서 이런 경우, Custom Hook을 만들어서 재사용을 할 수 있다.
1. Hook 클래스 정의
class HookScroller extends Hook<ScrollController> {
final AnimationController controller;
HookScroller(this.controller);
@override
_HookScrollerState createState() => _HookScrollerState();
}
class _HookScrollerState extends HookState<ScrollController, HookScroller> {
ScrollController scroller;
@override
void initHook() {
super.initHook();
scroller = ScrollController()
..addListener(() {
if (scroller.position.userScrollDirection == ScrollDirection.forward) {
hook.controller.forward();
} else if (scroller.position.userScrollDirection == ScrollDirection.reverse) {
hook.controller.reverse();
}
});
}
@override
ScrollController build(BuildContext context) => scroller;
@override
void dispose() {
scroller.dispose();
super.dispose();
}
}
2. 사용자 정의 메서드 추가
ScrollController scrollController(AnimationController controller) {
return Hook.use(HookScroller(controller)); // Hook을 위젯트리에 연결하는 역할
}
3. Hook 클래스에서 사용
class Home extends HookWidget {
@override
Widget build(BuildContext context) {
final hookAnimation = useAnimationController(duration: Duration(milliseconds: 500));
final hookScroll = scrollController(hookAnimation);
return Scaffold(
body: ListView.builder(
controller: hookScroll,
itemCount: 20,
itemBuilder: (context, index) => Container(
margin: EdgeInsets.all(10),
child: FadeTransition(
opacity: hookAnimation,
child: FlutterLogo(size: 100),
),
),
),
);
}
}
Hooks의 장점을 다시 정리하면,
1. 코드 간소화
- initState()와 dispose() 없이 상태 관리 가능
- 중복된 로직 제거로 코드 가독성 향상
2. 재사용성
- Custom Hook을 만들어 여러 화면에서 동일한 로직 재사용 가능
3. 유지보수 용이
- 대규모 프로젝트에서 상태 관리와 UI로직이 분리되어 유지보수가 쉬워짐
주의사항
- 모든 Hooks는 반드시 build() 메서드 내부에서 호출해야 한다.
- 작은 화면에서 StatefulWidget이 더 간단할 수 있으므로 무조건적인 사용은 지양하는 것이 좋다.
- Custom Hook은 초기 설정이 복잡할 수 있다. (다만 반복 작업이 많을 경우, 결국은 효율적인 방법)
결론
Flutter Hooks는 특히 대규모 프로젝트나 복잡한 UI 상태 관리를 요구하는 경우 매우 유용하며, Custom Hook을 적절히 잘 활용한다면 코드 재사용성을 극대화하고 유지보수를 용이하게 할 수 있을 것이다. 개인적으로는 거의 GetX를 사용하긴 하는데, GetX는 상태 관리와 의존성 주입에 중점을 둔 패키지고, Flutter Hooks는 위젯 상태 관리 로직을 간결하게 만드는데 포커스를 두기 때문에 약간 결이 다르긴하다. 기회가 된다면 현업에서도 적용해보면 좋을 것 같다는 생각이 든다.
아래 링크의 포스팅을 참고하여 정리한 내용입니다. 원문을 확인하고 싶으시면 아래 링크를 확인해주세요.
'Personal Posting > Flutter' 카테고리의 다른 글
Flutter 스피드 다이얼 구현 (0) | 2025.01.06 |
---|---|
Flutter 웹 로딩 속도 최적화 (0) | 2025.01.06 |
Dart/Flutter 프로토타입 디자인 패턴 (0) | 2025.01.04 |
Flutter 기반 함수형 에러핸들링 (0) | 2025.01.03 |
SOLID 원칙 Flutter 프로젝트에 적용하기 (1) | 2025.01.03 |