ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Flutter] Flutter 쉽게 코딩하기 - flutter_hooks
    앱개발 2019. 9. 19. 14:51

    Flutter Hooks: https://github.com/rrousselGit/flutter_hooks

    Flutter Hooks는 React의 Hooks와 이를 분석한 미디엄 글을 보고 영감을 받아 flutter에 맞도록 hook 을 구현한 패키지이다. StatefulStateless 를 구분할 필요 없이 하나의 HookWidget으로 모든 위젯을 표현할 수 있도록 도와주며, 위젯 lifecycle 및 로컬 state 관리와 관련하여 다양한 편의성을 제공한다.

    본 글에서는 간단하게 flutter_hooks 패키지를 사용하는 법을 살펴보도록 한다.

    설치하기

    패키지 설치는 여타 다른 패키지나 플러그인 설치와 동일하다. 실제 앱의 위젯을 구성하는데 사용될 위젯 패키지 이므로 pubspec.yamldependencies 섹션에 추가하면 된다.

    # pubspec.yaml 파일
    dependencies:
        flutter_hooks: any

    이후 다른 패키지 설치와 동일하게 flutter pub get 을 수행하면 된다.

    예제

    간단한 샘플 앱 2개를 보면서 사용법을 알아보자. 아래는 AnimationController 의 사용이 필요한 StatefulWidget 을 다루는 예제이다.

    Animation

    class AnimationWidget extends StatefulWidget {
        const AnimationWidget({Key key, @required this.duration}) : super(key:key);
        final Duration duration;
    
        @overrider
        _AnimationWidgetState createState() => _AnimationWidgetState();
    }
    class _AnimationWidgetState extends State<Example> with SingleTickerProviderStateMixin {
        AnimationController _controller;
    
        @override
        void initState() {
            super.initState();
            // 로직과 상관없는 코드 #1 - 컨트롤러 초기화
            _controller = AnimationController(vsync: this, duration: widget.duration);
        }
    
        @override 
        void didUpateWidget(Example oldWidget) {
            super.didUpdateWidget(oldWidget);
            if (widget.duration != oldWidget.duration) {
                _controller.duration = widget.duration; // 로직과 상관없는 코드 #2 - 업데이트
            }
        }
    
        @override
        void dispose() {
            _controller.dispose(); // 로직과 상관없는 코드 #3 - 컨트롤러 해제
        }
    
        @override
        Widget build(BuildContext context) {
            return Container();
        }
    }

    StatefulWidget 과 그에 따른 state를 정의하기 위한 State 클래스, 그리고 애니메이션 사용을 위한 mixin 추가를 위한 with 까지, 클래스 생성부터 부가적인 코드가 너무 많이 들어있는 것을 볼 수 있다. 또한 AnimationController 의 안전한 할당/해제를 위한 lifecycle 메소드까지 들어가서, 실제 UI나 로직을 위한 코드가 들어가는 build 메소드 외에 수십줄이 추가됨을 알 수 있다.

    flutter_hooks 는 이러한 부가적인 코드를 대신하여 실제 플러터 개발자는 온전히 UI와 로직에만 신경쓸 수 있도록 도와주는 위젯 패키지 이다. 기본적으로 Stateful이나 Stateless 위젯 대신 HookWidget 을 상속하여 원하는 위젯을 개발하면 되고, 기타 state 관리나 생명주기 관리 등은 같이 제공 되는 기본 Hooks 를 사용하거나, Hooks 를 커스텀하여 사용할 수 있다.

    위의 코드를 flutter_hooks 를 이용해 간소화 시킨 코드는 아래와 같다.

    import 'package:flutter_hooks/flutter_hooks.dart';
    class AnimationWidget extends HookWidget {
        const AnimationWidget({Key key, @required this.duration}):super(key:key);
    
        @override
        Widget build(BuildContext context) {
            final controller = useAnimationController(duration:duration);
            return Container(
                /* controller를 사용하는 코드 추가 */
            );
        }
    }

    거의 1/3 수준으로 줄어든 코드량을 볼 수 있다. 이는 flutter_hooks가 미리 정의한 useAnimationController 가 필요한 작업을 모두 대신해주기 때문이다. 본 글은 소개를 위한 글이므로 구현에 대한 자세한 설명은 생략한다.

    데이터 변화에 따른 위젯 업데이트

    플러터 기본 예제인 카운터를 비롯하여 다양한 위젯에서 데이터 변경에 따라 위젯을 업데이트 하고 싶은 경우 StatefulWidgetsetState를 사용한다. 그러나 이러한 코드는 위의 애니메이션 예제에서 보여줬듯이 부수적인 코딩을 요구한다. flutter_hooks를 사용하면 이 또한 간단하게 줄일 수 있다.

    import 'package:flutter_hooks/flutter_hooks.dart'
    class CounterWidget extends HookWidget {
        @override
        Widget build(BuildContext context) {
            final counter = useState(0);
            return GestureDetector(
                onTap: () => counter.value += 2;
                child: Text("Counter는 현재 ${counter.value} 입니다."),
            );
        }
    }

    매우 짧은 코드로 카운터를 완성했다! 기본 제공되는 useState 는 실제로는 ChangeNotifier 를 이용하여 구현된 것이다.

    주의점

    아래의 코드는 절대로 사용해서는 안되는 flutter_hook 사용법이다. 요약하자면 hook을 사용하는 순서는 항상 동일해야 하고, 조건에 따라 hook 사용은 선택적으로 해서는 안된다는 것이다.

    /* 금지 예제 1 ---------------- */
    if (condition) {
        useSomeHooksHere(); // if나 switch 등 조건문을 이용한 선택적 hook사용은 절대 해서는 안된다.
    }
    /* ---------------- */
    
    /* 금지 예제 2 ---------------- */
    Widget buildOrSomeFunction(BuildContext context) {
        useSomeHooks();
        if (condition) return Container();
        useOtherHooks(); // 이 또한 조건에 따라서 사용이 안 될수도 있기 때문에 금지한다. 
    }

    이는 flutter_hooks를 사용할 때 발생하는 state 들을 큐나 배열 형태로 차례로 관리하기 때문으로, 자세한 이유나 구현 방식을 알고 싶은 경우 제일 처음 언급한 react hook을 분석한 미디엄 글, 혹은 실제 flutter_hooks 코드를 보길 바란다.

    결론

    flutter_hooks는 react hooks로부터 영감으로 받아 flutter에 맞게 구현한 것으로, 플러터에 추가적인 기능을 넣은 것이 아니고, 원래 개발자가 추가해야할 코드들을 미리 구현해둔 것이다. 이를 이용하면 매우 짧은 코드로 간결하게 앱을 구현할 수 있으므로, 한번쯤 사용해보는것을 매우 추천한다.

    필자는 이걸 알게된 뒤로는 무조건 적으로 사용하며, 같은 개발자가 공개한 functional_widget 과 provider 도 함께 사용한다. provider는 너무 유명하므로 설명이 필요 없을 것이고, functional_widget도 한번 살펴보고 사용하길 바란다.

Designed by Tistory.