반드시 정할 필요는 없다.
다만, 타입이 명확해야 협업시 큰 도움이 됨.
차이 : final은 런타임, const는 컴파일 때 할당된다.
아직은 잘 모르겠으니, 실제 실습때 깊이 있게 다뤄볼 예정.
프로그램의 안정성을 위해 도입됨.
개념 : 해당 값은 비어있을 수 있다. or 비어있을 수 없다
예시 : null을 허용할경우, 변수'?'
와 같이 변수 우측에 ?
를 사용한다.
null을 허용하지 않을경우, 변수'!'
와 같이 변수 우측에 !
를 사용한다. (null일경우 에러 발생)
+, - , * /
등 계산에 사용되는 연산자이다.
특이점 : /
의 경우 int A / int B = double
형태의 값이 나오기도 함.
이는 에러가 발생.
그래서, 나눗셈의 경우 var
또는 새로운 타입(double C) 정의.
JS에서도 많이 애용했다.
String a = 10 <= 20 ? '참' : '거짓';
// 참
Dart에서 처음 보는 것이었다.
int num;
// error
위 num
은 빈 값이기 때문에, 컴파일 과정에서 에러가 발생한다.
int? num;
// null
다시, int에 ?
를 추가해 빈값을 허용한다.
int? num1;
int num2 = 10;
print(num1 + num2)
// error
print(num1! + num2) // !는 Null이 올 수 없다는 뜻
// 컴파일 과정에선 통과
// 실행시 error
print((num1 ?? 10) + num2)
// 여기서 ??는 num1에 값이 없다면 10.
// 20
따라서, null처리를 꼼꼼히 살펴야 겠다.
Flutter의 상태에 영향을 받지 않는 페이지.
정적 페이지다.
따라서, 상태가 변해도 해당 위젯의 변화는 없다.
반대로, 상태에 따라 변화가 필요하다면 해당 위젯을 사용한다.
아래는 IDE나 코드 편집기에서 stateful을 만든 기본 형태이다.
class ExampleWidget extends StatefulWidget {
const ExampleWidget({super.key});
State<ExampleWidget> createState() => _ExampleWidgetState();
}
class _ExampleWidgetState extends State<ExampleWidget> {
Widget build(BuildContext context) {
return const Placeholder();
}
}
생각보다 구조가 상당히 복잡했다.
Stateless위젯과는 다르게, createState()로 상태에 관한 클래스를 생성한 구조다.
왜 이런식의 구조를 사용하는가 찾아보니, 성능을 위해 상태(State)와 위젯(widget)을 분리
라고 한다.
해당 내용은 느낌으로는 React에 라이프 사이클과 비슷하다고 생각했다.
class ExampleWidget extends StatefulWidget {
... createState()
}
class _ExampleWidgetState extends State<ExampleWidget> {
/// 상태는 이곳에서 선언한다.
late int index;
/// 언더 스코어를 사용한 이유는 ExampleWidget(age : 10)과 같이 부모로 부터 받은 props를 사용할때 언더 스코어로 변수명을 지정한다고 한다.
late int _age;
/// initState로 상태값을 초기화 한다.
void initState() {
super.initState();
_age = widget.age; /// 부모로 부터 받은 props를 조회하려면 widget.props명 으로 조회
index = 3;
}
/// 상태는 이곳에서 선언한다.
Widget build(BuildContext context) {
return Container(child: Text('index -> $index'),),
}
}
위와 같이 작성하면 화면에 index -> 10
이라고 보일 것이다.
이제 상태가 변경될때 화면이 갱신되도록 바꿔 보겠다.
class ExampleWidget extends StatefulWidget {
... createState()
}
class _ExampleWidgetState extends State<ExampleWidget> {
/// 상태는 이곳에서 선언한다.
late int index;
/// 언더 스코어를 사용한 이유는 ExampleWidget(age : 10)과 같이 부모로 부터 받은 props를 사용할때 언더 스코어로 변수명을 지정한다고 한다.
late int _age;
/// initState로 상태값을 초기화 한다.
void initState() {
super.initState();
_age = widget.age; /// 부모로 부터 받은 props를 조회하려면 widget.props명 으로 조회
index = 3;
}
/// 상태는 이곳에서 선언한다.
Widget build(BuildContext context) {
/// GestureDetector는 사용자로부터 특정 동작을 감지한다.
return GestureDetector(
/// 화면 한번 터치
onTap: () {
/// 해당 부분이 매우 중요한데, setState((){...})가 없다면 상태값에 변경이 있더라도 화면이 변경되지 않는다.
setState(() {
if(index == 5) {
index = 0;
return;
}
index++;
});
},
child: Container(
/// 이런 식으로 UI의 변화를 줄 수 도 있다.
color: Colors.blueAccent.withOpacity(index * 0.2),
child: Text('index -> $index, props Age = $_age'),
),
);
}
}
여기서 신기한건, setState로 꼭 로직을 감싸지 않아도 정상 실행 된다.
GestureDetector(
onTap: () {
setState(() {}); /// 정상 실행
if(index == 5) {
index = 0;
return;
}
index++;
},
child: Container(...),
);
... 공부 내용 갱신중