기본적으로 flutter 프로젝트를 시작하면 생성되는 main.dart 파일을 기준으로 stateless와 stateful widget을 비교해볼 것이다.
코드를 보면 크게 5개의 코드 덩어리로 분류할 수 있다.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget{..생략..}
class MyHomePage extends StatefulWidget{..생략..}
class _MyHomePageState extends State<MyHomePage>{..생략..}
차례대로 각각의 코드 덩어리가 의미하는 부분을 알아보자.
이제 진짜 나머지 3개의 코드 덩어리로 statelessWidget과 statefullWidget에 대해 알아보자.
참고로 미리 말하자면,
class MyApp extends StatelessWidget{..생략..}
-> stateless
class MyHomePage extends StatefulWidget{..생략..}
-> stateful
class _MyHomePageState extends State<MyHomePage>{..생략..}
-> stateful이다.
그리고 vscode에서 stl까지 치면 stateless를 상속받는 class 틀이 딱 나옴!
stateful은 stf
StatelessWidget 클래스는 상태가 없고, 상태를 가지지 않는 위젯을 구성하는 기본 클래스다. 여기서 상태를 가지지 않는다는 것은 한 번 그려진 후 다시 그리지 않는 경우이며, 이러한 클래스는 프로퍼티(property)로 변수를 가지지 않는다.(상수는 가짐)
runApp()함수에 전달된 MyApp 클래스는 다음과 같이 정의되어있다.
class MyApp extends StatelessWidget{
@override
Widget build(BuildContext context){
return MaterialApp(..생략..);
}
}
따라서
class MyApp extends StatelessWidget{
-> statelessWidget 클래스를 상속받은 MyApp 클래스는
return MaterialApp(..생략..);
MaterialApp 클래스의 인스턴스를 작성해 반환한다.
그럼 MyApp 클래스가 반환하는 MaterialApp클래스는 뭘까?
build() 메소드가 반환하는 MaterialApp 클래스는 다음과 같다.
return MaterialApp(
title: 'flutter',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'flutterdd'),
);
이 코드에서는 title, theme, home 세 가지 이름있는 인수를 설정한다. 이 프로퍼티들을 설정하여 위젯의 속성을 표현한다.
title : 제목
theme : 테마. 코드에서는 파랑계열의 색상 테마로 설정함.
home : home에 작성하는 위젯이 실제 이 앱이 표시하는 위젯이 됨.
dart 언어에는 이름있는인수와 이름없는인수(일반 인수)가 있다. 위젯에 따라 각각 사용 방법이 다르다.
- 이름 있는 인수는 인수 앞에 인수명을 쓴다.
ex. MyHomePage(title: 'hello')- 이름 없는 인수명 안 쓴다.
ex. Text('hello')
플러터에서 이름있는인수는 클래스의 프로퍼티에 값을 할당하는 것이며, 그 모양새는 클래스의 속성을 의미한다.
상태가 있는 위젯을 정의할 때는 StatefulWidget 클래스를 사용한다. main.dart 코드에서 StatefulWidget 클래스는
StatefulWidget
을 상속받은 MyHomePage 클래스와State<MyHomePage> 클래스
를 상속받은 _MyHomPageState 클래스로 구성된다.각각의 클래스 안에 작성된 코드를 자세히 들여다보자.
class MyHomePage extends StatefulWidget{
MyHomePage({Key key, this.title}) : super(key: key); //-> MyHomePage 클래스의 생성자는 key와 title 프로퍼티를
// 옵션으로 받아서 super 키워드로 부모 클래스의 생성자에 key를 전달한다.
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePage extends State<MyHomePage>{
int _counter = 0;
...생략...
@override
_MyHomePageState createState(
int _counter = 0;
...생략...
@override
Widget build(BuildContext context){//_MyHomePageState 클래스의 상태에 따라
//화면에 그려질 코드를 여기에 작성한다.
return Scaffold(...생략...);
}
}
@override
_MyHomePageState createState() => _MyHomePageState();
-> MyHomePage 클래스에는 상속받은 createState()메소드를 재정의하여 _MyHomePageState 클래스의 인스턴스를 반환한다.
텍스트
class _MyHomePage extends State<MyHomePage>{}
-> 상태 클래스
MaterialApp 클래스에서 home 프로퍼티에 MyHomePage 인스턴스를 생성하고 인수로 전달하며, 그와 동시에 MyHomePage의 title 인숫값으로 'flutterdd'를 전달했다.
return MaterialApp(
title: 'flutter',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'flutterdd'),
);
이렇게 전달 받은 title 인숫값은 MyHomePage 클래스의 생성자의 this.title 매개변수로 전달되어 필드 상수인 String title에 대입된다.
class MyHomePage extends StatefulWidget{//생성자
MyHomePage({Key key, this.title}) : super(key: key); //-> MyHomePage 클래스의 생성자는 key와 title 프로퍼티를
// 옵션으로 받아서 super 키워드로 부모 클래스의 생성자에 key를 전달한다.
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePage extends State<MyHomePage>{
@override
Widget build(BuildContext context){//_MyHomePageState 클래스의 상태에 따라
//화면에 그려질 코드를 여기에 작성한다.
return Scaffold(
appBar: Appbar(
title: Text(widget.title),
),
);
}
}
이렇게 위젯 사이의 데이터 전달은 생성자를 활용한다.
상태 클래스에서 StatefulWidget 클래스에 접근하려면 widget 프로퍼티를 사용한다.
그럼 이제 상태가 변화하는 statefulWidget의 상태가 어떻게 변경되는지 알아보자.
State 클래스에는 주로 상태를 저장할 변수들과 그 변수를 조작할 메서드를 작성한다.
main.dart 카운터 앱의 state 클래스를 보면 incrementCount()메소드로 setState() 메소드를 실행시킨다.
[stateful, 동적인 화면이 되는 원리 정리]
MyHomePage 클래스는 StatefulWidget의 서브클래스이며 상태를 가질 수 있다. 그리고 그 상태는 State 클래스의 서브클래스로 정의한다. _counter 변수 값이 변경될 때마다 화면을 다시 그리면 동적인 화면을 가진 앱이 되는 거다.
진짜 정리