Widget, StatelessWidget, StatefulWidget
참고자료
- Stateful Widget, Stateless Widget
Widget
- UI 를 표현하는 Dart 의 클래스
- 화면에 나타나는 것에 대한 데이터와 설정이 모여 있습니다.
플러터의 모든 요소는 위젯이며, 위젯이 위젯을 포함하며 위젯들이 모인 Widget Tree 를 기반으로 화면을 렌더링합니다.
대표적인 Widget 들은 아래와 같습니다.
- Scaffold, Stack, Row, Colum : 레이아웃
- Center, Padding : 정렬, 패딩
- Button, Toast, MenuDrawer : 구조
- FadeInPhoto, Transform : 에니메이션
- TextStyle, Color : 스타일
Stateless Widget
상태가 없는 위젯을 의미합니다. 위젯을 어느 시점에 트리에서 제거할지 언제 리빌드할지가 외부로부터 결정됩니다.
불변이라는 의미는 아니며, 외부의 정보에 따라서 변합니다. 다만 상태를 가지고 있지 않습니다. React 를 예로 들면 리덕스의 store,state 같은 상태변수를 가지고 있지 않은 컴포넌트를 의미합니다.
Stateless Widget 은 vscode 또는 Android Studio 에서 제공하는 단축키로 쉽게 생성할수도 있고, 직접 작성해도 됩니다. Stateless Widget 은 아래의 두 요소로 이뤄집니다.
- 생성자 (constructor)
- build(BuildContext context) 메서드
- Widget 을 리턴하는 메서드입니다.
- build() 메서드가 리턴하는 Widget 으로 뷰를 Rendering 할 수 있습니다.
StatefulWidget
State
객체를 갖는 위젯- setState() 메서드를 가지며, setState() 를 통해서 상태에 변화가 생기면 위젯이 다시 렌더링됩니다.
기본적인 클래스의 구조는 아래와 같습니다.
class Example extends StatefulWidget {
// (1)
const Example({ Key? key }) : super(key: key);
// (2)
@override
_ExampleState createState() => _ExampleState();
}
// (3)
class _ExampleState extends State<Example> {
@override
Widget build(BuildContext context) {
return Container(...);
}
}
(1)
- 생성자입니다.
(2) : _ExampleState createState() => _ExampleState()
- State 타입의 구체 객체인 _ExampleState 객체를 새롭게 생성해서 return 합니다.
- createState() 함수는 State 객체를 생성하는 역할을 합니다.
(3) : class _ExampleState extends State<Example> {...}
Example
위젯을 감싸는_ExampleState
라는 이름의 State 객체를 생성했습니다.
setState - e.g.
Android Studio 에서 Flutter Project 를 생성합니다.
만들어진 예제 코드를 보면 아래와 같습니다. 아래 코드에서 (2) 로 표시한 부분이 setState() 를 사용하는 부분입니다.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
// (1)
int _counter = 0;
// (2)
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
floatingActionButton: FloatingActionButton(
// (3)
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
- (1) : 변경이 필요한 상태값을 State 객체 내부에 private 객체로 선언해줍니다.
- (2) : 상태 변경이 필요한 부분의 함수에서 setState() 함수를 호출합니다.
- (3) : onPressed 이벤트에 대해서
_incrementCounter()
함수를 호출하도록 지정해줘서 onPressed 이벤트 발생시마다 setState() 함수가 호출되게 됩니다.
참고
private 접근자
dart 에서 클래스나 프로퍼티,메서드 앞에 언더바를 붙이면 private 를 의미합니다.
class Example extends StatefulWidget {
// (1)
const Example({ Key? key }) : super(key: key);
// (2)
@override
_ExampleState createState() => _ExampleState();
}
// (3)
class _ExampleState extends State<Example> {
@override
Widget build(BuildContext context) {
return Container(...);
}
}