Stateless vs Stateful Widget

샤워실의 바보·2023년 12월 4일
0
post-thumbnail
import 'package:flutter/material.dart';
import 'package:tiktok_clone/constants/gaps.dart';
import 'package:tiktok_clone/constants/sizes.dart';
import 'package:tiktok_clone/features/authentication/email_screen.dart';
import 'package:tiktok_clone/features/authentication/widgets/form_button.dart';

class UsernameScreen extends StatefulWidget {
  const UsernameScreen({super.key});

  
  State<UsernameScreen> createState() => _UsernameScreenState();
}

class _UsernameScreenState extends State<UsernameScreen> {
  final TextEditingController _usernameController = TextEditingController();

  String _username = "";

  
  void initState() {
    super.initState();
    _usernameController.addListener(() {
      setState(() {
        _username = _usernameController.text;
      });
    });
  }

  
  void dispose() {
    _usernameController.dispose();
    super.dispose();
  }

  void _onNextTap() {
    if (_username.isEmpty) return;
    Navigator.of(context).push(
      MaterialPageRoute(
        builder: (context) => const EmailScreen(),
      ),
    );
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text(
          "Sign up",
        ),
      ),
      body: Padding(
        padding: const EdgeInsets.symmetric(
          horizontal: Sizes.size36,
        ),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Gaps.v40,
            const Text(
              "Create username",
              style: TextStyle(
                fontSize: Sizes.size24,
                fontWeight: FontWeight.w700,
              ),
            ),
            Gaps.v8,
            const Text(
              "You can always change this later.",
              style: TextStyle(
                fontSize: Sizes.size16,
                color: Colors.black54,
              ),
            ),
            Gaps.v16,
            TextField(
              controller: _usernameController,
              decoration: InputDecoration(
                hintText: "Username",
                enabledBorder: UnderlineInputBorder(
                  borderSide: BorderSide(
                    color: Colors.grey.shade400,
                  ),
                ),
                focusedBorder: UnderlineInputBorder(
                  borderSide: BorderSide(
                    color: Colors.grey.shade400,
                  ),
                ),
              ),
              cursorColor: Theme.of(context).primaryColor,
            ),
            Gaps.v28,
            GestureDetector(
              onTap: _onNextTap,
              child: FormButton(disabled: _username.isEmpty),
            ),
          ],
        ),
      ),
    );
  }
}

import 'package:flutter/material.dart';

import '../../../constants/sizes.dart';

class FormButton extends StatelessWidget {
  const FormButton({
    super.key,
    required this.disabled,
  });

  final bool disabled;

  
  Widget build(BuildContext context) {
    return FractionallySizedBox(
      widthFactor: 1,
      child: AnimatedContainer(
        padding: const EdgeInsets.symmetric(
          vertical: Sizes.size16,
        ),
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(Sizes.size5),
          color:
              disabled ? Colors.grey.shade300 : Theme.of(context).primaryColor,
        ),
        duration: const Duration(milliseconds: 500),
        child: AnimatedDefaultTextStyle(
          duration: const Duration(milliseconds: 500),
          style: TextStyle(
            color: disabled ? Colors.grey.shade400 : Colors.white,
            fontWeight: FontWeight.w600,
          ),
          child: const Text(
            'next',
            textAlign: TextAlign.center,
          ),
        ),
      ),
    );
  }
}

FormButtonStatelessWidget으로 정의된 것은 Flutter의 위젯 트리와 상태 관리 방식에 기반합니다. 여기서 중요한 점은 상태의 변경이 어디서 발생하고, 어떻게 처리되는지를 이해하는 것입니다.

StatelessWidget vs StatefulWidget

  • StatelessWidget: 이 위젯은 상태를 내부적으로 관리하지 않습니다. 즉, StatelessWidget은 생성 시 전달받은 매개변수를 기반으로 UI를 렌더링하고, 이 매개변수들이 변경되지 않는 한 다시 렌더링되지 않습니다.
  • StatefulWidget: 이 위젯은 내부 상태를 가지며, 상태가 변경될 때마다 UI를 업데이트할 수 있습니다.

FormButton의 역할과 동작

  • FormButton은 비활성화 여부 (disabled)를 부모 위젯으로부터 매개변수로 전달받습니다. 이 매개변수는 _username.isEmpty에 의해 결정되며, _usernameUsernameScreen의 상태입니다.
  • UsernameScreen에서 TextEditingController (_usernameController)의 변화에 따라 _username이 업데이트되고, 이로 인해 UsernameScreen이 리렌더링됩니다.
  • 리렌더링 과정에서 FormButton에 새로운 disabled 값이 전달되며, 이는 FormButton의 외관을 결정합니다.

왜 FormButton은 StatelessWidget인가?

  • FormButton 자체는 내부 상태를 가지지 않습니다. 그것의 모양과 동작은 전적으로 부모 위젯 (UsernameScreen)으로부터 전달받은 disabled 매개변수에 의존합니다.
  • 상태의 변경은 UsernameScreen에서 관리되고, FormButton은 단순히 그 상태에 따라 다르게 보여질 뿐입니다. 따라서 FormButton 내부에 별도의 상태 관리 로직이 필요하지 않으며, StatelessWidget으로 충분합니다.

결론적으로, FormButtonStatelessWidget으로 적절히 구현된 것입니다. 상태 변경에 따른 UI 업데이트는 상태를 소유한 UsernameScreen이 담당하며, FormButton은 단순히 전달받은 매개변수에 따라 렌더링됩니다. 이는 Flutter의 효율적인 상태 관리 및 위젯 트리 업데이트 메커니즘을 잘 활용하는 사례입니다.

profile
공부하는 개발자

0개의 댓글