[Flutter] Stateful Widget

JH Cho·2023년 1월 23일
0

Flutter

목록 보기
4/8

Stateful Widget

Stateful Widget은 변경 가능한 위젯이다.

  • state는 위젯이 빌드될 때 동기적으로 읽을 수 있고 위젯의 lifecycle동안 변경 가능한 정보이다.
  • Stateful 위젯은 두 가지로 나뉜다.
  1. 상태가 없는 위젯
  2. state 위젯은 위젯에 들어갈 데이터와 UI를 넣는 곳
    (데이터가 변경되면 해당 위젯도 변경된다.)

기본 코드 구성

@immutable
class App extends StatefulWidget {
  const App({super.key});

  @override
  State<App> createState() => _AppState();
}

class _AppState extends State<App> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        backgroundColor: const Color(0xFFF4EDDB),
        body: Container(),
      ),
    );
  }
}

Stateful로 바꾸고

이런 에러가 발생했다.
이 글을 보고 해결했음.

  • main()이나 initState() 메서드 내에서 변경을 했을 때 핫 리로드가 실패하는 현상으로 VM을 재부팅하여 다시 앱을 실행하면 해결됨.

setState()

  int counter = 0;

  void onCliked() {
    // 단순히 아래처럼 counter의 값을 변경하는 것은
    // 플러터에서 알아차리지 못함.
    // counter = counter + 1;

// react처럼 setState 함수를 이용해서 알려줘야 함.
// 무조건 counter ++; 이 setState 내에 있어야 하는 것은 아니고
// setState함수가 실행되면서 build메서드를 실행시킴.
    setState(() {
      counter++;
    });
  }

Recap

  List<int> numbers = [];
  void onCliked() {
    setState(() {
      numbers.add(numbers.length);
    });
  }
  
  //build
  for (var n in numbers) Text('$n'),

flutter에서는 생각보다 state가 많이 사용되지 않음.

build context

  • context는 부모 요소들의 모든 정보를 담고 있다.
  • buildContext는 위젯 트리에서 위젯의 위치를 제공
  • 이를 통해 상위 요소 데이터에 접근 가능
Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        textTheme: const TextTheme(
          titleLarge: TextStyle(
            color: Colors.red,
          ),
        ),
      ),
        
        
// 자식 MyLargeTitle
//MyLargeTitle은 MaterialApp의 자식이고
//부모의 ThemeData를 사용하기 위해서 context를 사용.
  Widget build(BuildContext context) {
    return Text(
      'My Large title',
      style: TextStyle(
        fontSize: 30,
        // context로 부모 요소에 접근하여 데이터를 가져오는 방법.
        color: Theme.of(context).textTheme.titleLarge?.color,
      ),
    );

Widget LifeCycle

initState

  • 위젯이 처음 생성될 때 한 번 호출되는 메서드
class _MyLargeTitleState extends State<MyLargeTitle> {
  //initState를 사용하지 않고 아래처럼 해도 됨.
  //근데도 initState를 사용하는 상황
  // 부모 요소에 의존하는 데이터를 초기화해야 하는 경우
  // API에서 데이터를 받아와 이니셜라이즈.
  // 그 때 build 메서드보다 initState가 항상 먼저 호출 됨.
  int count = 0;

  //상태를 초기화하기 위한 메서드(옵션)
  @override
  void initState() {
    super.initState();
    print('initState!');
  }

  @override
  Widget build(BuildContext context) {
    print('build!');

    return Text(
      'My Large title',
      style: TextStyle(
        fontSize: 30,
        // context로 부모 요소에 접근하여 데이터를 가져오는 방법.
        color: Theme.of(context).textTheme.titleLarge?.color,
      ),
    );
  }
}
  • initState가 먼저 호출되는 것 증명

dispose

  • 위젯이 제거될 때 호출되는 메서드
    • API업데이트나 이벤트 리스너 구독을 취소하거나
    • form의 리스너로부터 벗어나고 싶을 때 사용.

위젯이 제거되기 전에 실행하고 싶은 코드를 기입.

// 토글 만들어주고.
class _AppState extends State<App> {
  bool showTitle = true;

  void toggleTitle() {
    setState(() {
      showTitle = !showTitle;
    });

// 
showTitle ? const MyLargeTitle() : const Text('nothing'),
              IconButton(
                  onPressed: toggleTitle,
                  icon: const Icon(Icons.remove_red_eye))
  }

토글 눌러서 MyLargeTitle()이 제거될 때 디버그 콘솔에 dispose가 출력.

요약
stateful widget은 lifecycle을 가지고 있다.
가장 중요한 메서드는 initState와 dispose, build이다.

  • build: UI 생성
  • initState : build 이전에 호출되는 메서드
  • dispose : 위젯이 위젯트리에서 제거될 때 호출
profile
주먹구구식은 버리고 Why & How를 고민하며 프로그래밍 하는 개발자가 되자!

0개의 댓글