한줄 요약
- Hook 패키지는 자주 사용하는 로직을 Hook으로 추상화하여 쉽게 쓸수 있게 만들어주는 패키지이다.
Hook 라이브러리는 Flutter의 StatelessWidget
와 StatefulWidget
을 대신하는 HookWidget
을 제공하는 라이브러리 입니다. HookWidget을 사용하면 해당 위젯이 가진 Hook
함수를 사용할 수 있습니다.
StatefulWidget
내부에서 setState
함수를 사용할 수 있는 것과 유사하다고 보면 됩니다.
StatefulWidget
의 단점 중 하나는 기본적인 로직을 재사용하기 힘들다는 점 입니다. 대표적인 예시가 바로 Animation 구현 입니다.
class Example extends StatefulWidget {
final Duration duration;
const Example({Key? key, required this.duration})
: super(key: key);
_ExampleState createState() => _ExampleState();
}
class _ExampleState extends State<Example> with SingleTickerProviderStateMixin {
AnimationController? _controller;
void initState() {
super.initState();
_controller = AnimationController(vsync: this, duration: widget.duration);
}
void didUpdateWidget(Example oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.duration != oldWidget.duration) {
_controller!.duration = widget.duration;
}
}
void dispose() {
_controller!.dispose();
super.dispose();
}
Widget build(BuildContext context) {
return Container();
}
}
Animation을 구현할 때 Flutter은 코더에게 Animation을 구현하는 로직을 세세히 정의할 것을 요구합니다. 이 방식은 코더가 너무 많은 작업을 하게 만든다는 단점을 가지고 있습니다.
코더가 직접 관리해야 하는 부문
또한, 이렇게 만든 로직은 다른 클래스에 재활용할 수 없습니다. 애니메이션을 위젯에 구현할 때마다 프로그래머는 애니메이션을 구현하는 로직을 반복해서 적어주어야 합니다.
Hook은 이에 대한 해결책으로 ‘자주 사용하는 로직을 미리 정의하여 필요할 때 꺼내다 쓴다’를 제시하고 있습니다. 이렇게 미리 정의한 정의한 로직패턴을 해당 패키지에서는 Hook
이라고 부릅니다.
미리 정의된 로직 = Hook
간단한 예시를 살펴보도록 하겠습니다.
class Counter extends StatefulWidget {
_CounterState createState() => _CounterState();
}
class _CounterState extends State<Counter> {
int _counter = 0;
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => setState(() {
_counter++;
}),
child: Text(_counter.toString()),
);
}
}
위 예시는 화면을 탭했을 때 숫자가 늘어나는 간단한 위젯입니다. 해당 로직은 앱을 만들때 너무나도 흔하게 보는 패턴 중 하나입니다.
HookWidget은 해당 패턴을 이미 가지고 있습니다. 우리가 할 일은 HookWidget에 미리 정의된 함수를 가져와 해당 패턴에 적용하는 일입니다. HookWidget이 가진 로직은 다음 사이트에서 확인 가능합니다.
class Counter extends HookWidget {
Widget build(BuildContext context) {
final counter = useState(0);
return GestureDetector(
// automatically triggers a rebuild of the Counter widget
onTap: () => counter.value++,
child: Text(counter.value.toString()),
);
}
}
위 코드에서 새로운 변수를 만들고 변수의 변화를 추적하는 로직, hook
,은 useState
입니다. 위의 예시는 useState
hook을 사용하여 숫자가 늘어나고, 해당 변화가 화면에 표시되는 로직을 최소한의 코드로 구현햇습니다.
위 코드를 보고 굳이 hook을 쓸 이유를 찾지 못할 수도 있습니다. 하지만 작성자의 입장이 아니라 코드를 읽는 사람의 입장으로 돌아가 보겠습니다.
int _counter = 0;
위 코드를 봤을 때 우리는 해당 변수의 역할을 오직 이름과 타입에서만 추측할 수 있습니다. 하지만 Hook으로 이를 표시한다면 더 많은 정보를 얻을 수 있습니다.
final counter = useState(0);
해당 counter를 hook으로 표현한다면 counter 변수가 State로서 변화되고, 추적되고 있다는 점을 쉽사리 알 수 있습니다. 한 줄의 코드가 더 많은 정보를 추상화하여 전달해 주고 있습니다.