2026.01.07 (수)

직접 설치하지 않고 이미 완성된 인프라 같은느낌
백엔드 종합 서비스
데이터를 저장하는 서랍장, 창고!
Cloud NoSQL Database
엑셀처럼 칸이 딱 정해진 방식이 아니라, JSON 형태의 유연한 문서 구조를 가지고 있음
데이터가 바뀌면 앱에 즉시 반영된다
서버 코드를 짤 필요 없이 Flutter 코드만으로 DB를 제어 가능
flutter configure 입력 후 원하는 환경 선택 (Android, ios, wed 등등)flutter pub add firebase_core / flutter pub add cloud_firestoremain()함수에서 Firebase 사용할 준비🔻 앱 시작 될 때 먼저 실행하기 (Firebase 초기화) (main 함수에서 실행)
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,);
runApp(MyApp());
}
🔻 데이터 다루기 (CRUD)
Create : 새로운 문서 저장firestore.collection('users').add({'name': '지니'});
Read : 데이터를 가져옴firestore.collection('users').get();
Update : 특정 필드만 변경docRef.update({'age' : 20});
Delete: 문서를 삭제docRef.delete();
비동기 처리 필수
DB 작업은 시간이 걸리는 작업으로 반드시 async/await 사용해서 데이터가 올 때까지 기다려줘야함!
기존 알고 있던 TextField가 아니야 Form이 추가된
유효성 검사 기능이 있는 똑똑한 입력창
사용자가 입력을 제대로 했는지 검사 후 틀리면 에러 메시지를 띄워줌
입력값이 비어있는지, 혹은 형식에 맞는지 검사하는 로직을 넣는 곳
검사가 끝난 후 입력된 값을 변수에 저장할 때 사용함
입력창에 힌트텍스트("내용을 입력하세요") 혹은 테두리 디자인 가능
Form 위젯의 상태(FormState)를 제어한다. 예를 들어, 전송 버튼을 눌렀을 때 "자, 이제 폼 안에 있는 모든 입력창들을 검사해"라고 명령을 내리는 역할을 한다
버튼은 보통 Form 위젯 밖에 있거나 하위에 있는데, 버튼을 눌렀을 때 Form 전체의 유효성 검사를 한꺼번에 실행할 수 있음
GlobalKey는 위젯 트리 어디에서든 특정 위젯의 상태(State)에 접근할 수 있게 해주는 특별한 친구..
공식문서: https://api.flutter.dev/flutter/widgets/GlobalKey-class.html
final _formKey = GlobalKey<FormState>();
Form 위젯의 key 속성에 위에서 만든 _formKey를 연결
Form의 자식으로 TextFormField를 넣고 각자의 validator를 작성
_formKey.currentState!.validate()를 호출합니다.
사용자 결과값이
true면? -> 모든 입력이 정상 확인, 다음 단계로 이동.
false면? -> 입력창에 빨간 에러 메시지 자동 표시!
오늘 WritePage에 작성한 TextFormField와 GlobalKey
// GlobalKey 유효성 검사를 위해 3개의 TextEditingController 생성
class _WritePageState extends State<WritePage> {
TextEditingController writeController = TextEditingController();
TextEditingController titleController = TextEditingController();
// GlobalKey 선언, FormState 제너릭 명시 (StatefulWidget 내에서 선언)
GlobalKey<FormState> formKey = GlobalKey<FormState>();
// dispose 함수 실행되면 화면에서 종료되고, TEC 완전히 종료될 수 있도록 각각 선언해주기
@override
void dispose() {
writeController.dispose();
titleController.dispose();
super.dispose();
}
// 완료 버튼 클릭 시에 유효성 검사 formKey
GestureDetector(
onTap:() {
final result = formKey.currentState?.validate() ?? false;
},
// 최상위는 Form 으로 감싸기
body: Form(
key: formKey, // 완료 버튼 클릭 시, 유효성 검사
child: ListView(
children: [
TextFormField(
controller: writeController,
decoration: InputDecoration(hintText: '작성자'),
validator: (value) {
if (value?.trim().isEmpty ?? true) {
return '작성자를 입력해주세요';
}
return null;
},
),
TextFormField(
controller: titleController,
textInputAction: TextInputAction.done,
decoration: InputDecoration(hintText: '제목'),
// validator 함수로 유효성 검사
validator: (value) {
if (value?.trim().isEmpty ?? true) {
return '제목을 입력해주세요';} // 유효성 검사 실패 시, 글자 출력
return null; // null 반환 시에 유효성 검사 성공
},
),