앞서 포스팅한 custome widget을 만드는 방법은 많진 않지만 우리는 Stateless한 Widget을 만들었다.
이는 내부적으로 바뀌는 값이 있다면 매우 잘 못 된 선택이다.
어떠한 값을 받아서 어떠한 값을 return하는 경우에는 더더욱이 말이다
StateFull Widget 닉값을 한다. 즉, 내부적으로 state를 갖는다. 이는 변하며 또 UI에 영향을 미친다.
class DiceRoller extends StatefulWidget {
const DiceRoller({super.key});
State<DiceRoller> createState() {
return _DiceRollerState();
}
}
StatefullWidget은 non-final하지만 그럼에도 불구하고 생성자함수는 const라고 지정할 수 있다.
왜냐하면 2번째 클래스를 갖고있기 때문이다.
StateFull Widget은 Stateless Widget과 다르게 클래스를 생성할 때 build()
를 사용하지 않는다.
대신 createState()
를 쓴다. 이 함수는 항상 State
type을 return하고 이는 Flutter 에서 제공하는 타입이다.
그리고 State이긴 한데 어떤 State냐 바로 본인 State를 뜻한다.
return값은 항상 메서드에 사용되는 type를 리턴해야한다.
그리고 그 값은 또 다른 class에서 생성된다.
즉, StatefullWidget를 생성한다면 항상 2개의 클래스를 다뤄야한다.
그래서 2번째 클래스의 이름은 통상 _
접두어가 붙고 가운데 1번째 클래스 이름이 붙고 접미어로 State
가 붙는다.
class _DiceRollerState extends State<DiceRoller> {
var activeDiceImage = 'assets/images/dice-2.png';
void rollDice() {
activeDiceImage = 'assets/images/dice-4.png';
}
Widget build(context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Image.asset(
activeDiceImage,
width: 200,
),
ElevatedButton(
onPressed: rollDice,
style: TextButton.styleFrom(
padding: const EdgeInsets.only(
top: 10,
),
foregroundColor: Colors.white,
textStyle: const TextStyle(fontSize: 28),
),
child: const Text('주사위 굴리귀!'),
),
],
);
}
}
앞서 _
접두어가 붙는다 했는데 이 _
의 의미는 바로 "비공개"라는 것이다.
이렇게 _
접두어를 붙여놓으면 다른 곳에서 import를 하더라도 해당 클래스에 접근할 수 없다.
State<1번째클래스>
이다.build()
메서드를 추가하면 된다.물론 Statefull한 widget을 만들고 해당 state를 관리하고 return하기 위해 2번째 클래스도 만들었지만 이는 충분하지 않다.
왜냐하면 플러터는 기본적(default)으로 이를 무시한다.
무슨 말이야 state가 변경되었다고 build 메서드를 재실행하고 ui를 재평가(업데이트)하지 않는다는 것이다.
바로 setState라는 함수로 update를 해주면 된다.
setState는 StatefullWidet를 만들 때 => _어쩌구State 라는 2차 익명class를 만든다 하였고 이때 2차 class는 State를 상속받는다고 하였다.
바로 이 State 객체에서 받아온 함수가 바로 setState()이다.
즉, State를 상속받아야 setState()를 쓸 수 있따.
setState는 무조건 함수를 인수로 갖는다.
그리고 실행문 안에서 비로소 obj 변수, 객체 변수를 최신화할 수 있다.
그리고 해당 build 함수가 실행되면 비로소 플러터는 전과 다른 UI를 찾아 업데이트를 할지 말지 결정한다.
즉, setState가 실행되면 build가 다시 실행고 이때 플러터가 전과 다른 UI들을 찾아 바꿔야할 곳을 전부 바꾼다.
_
키워드는 다른 곳에서 쓰지 않겠다. 즉, private하게 쓰겠다는 뜻이다.
이는 Class 뿐만 아니라 state 클래스 내부에 있는 변수와 메서들에게도 적용가능한 부분이다.
따라서 Class가 priavte(_
) 키워드가 없다면 밑에 속성, 메서들에도 없어야 한다. 왜? => Class에 접근은 가능한데 그 하위에 있는 요소들을 전혀사용할 수 없게되기 때문이다.
void rollDice() {
var diceRoll = Random().nextInt(6)+1;
setState(() {
activeDiceImage = 'assets/images/dice-$diceRoll.png';
});
}
$
키워드는 쓰되 뒤에 {}
는 붙이지 않아도 된다.