신승호. 2023. 3. 15. 15:56

과제를 진행하기 위해서 아래의 설정을 맞춰주세요.

프로젝트에 컬렉션 (post)를 만들고 2가지 Document를 만들어 다음의 값을 넣도록 한다.

  • 문서명은 자동생성할 수 있도록 한다.
  • 필드값은 content, likes, title를 같도록 하며, 데이터타입은 다음과 같다.
    • content - string
    • title - string
    • likes - number
  1. 지금까지 JSON 데이터를 불러와서 Class에 적용시키기 위해 Serialization을 진행하였다. Firebase에서 이를 편하게 적용시킬 수 있도록하는 메서드 (withConverter)를 제공하는데,
    • lib/model/post.dart
// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'dart:convert';

class Post {
  String? id;
  String title;
  String content;
  int likes;
  Post({
    required this.id,
    required this.title,
    required this.content,
    required this.likes,
  });

  Map<String, dynamic> toMap() {
    return <String, dynamic>{
      'id': id,
      'title': title,
      'content': content,
      'likes': likes,
    };
  }

  factory Post.fromMap(Map<String, dynamic> map) {
    return Post(
      id: map['id'] as String?,
      title: map['title'] as String,
      content: map['content'] as String,
      likes: map['likes'] as int,
    );
  }

  String toJson() => json.encode(toMap());

  factory Post.fromJson(String source) =>
      Post.fromMap(json.decode(source) as Map<String, dynamic>);
}

lib/view/page/assignment_page.dart

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';

class AssignmentPage extends StatefulWidget {
  const AssignmentPage({super.key});

  @override
  State<AssignmentPage> createState() => _AssignmentPageState();
}

class _AssignmentPageState extends State<AssignmentPage> {
  var ref = FirebaseFirestore.instance.collection('post').withConverter(
    fromFirestore: (snapshot, _) => Post.fromMap(snapshot.data()!),
    toFirestore: (data, _) => data.toMap(),
  );

  Future<List<QueryDocumentSnapshot<Post>>> readData() async {
    var items = await ref.get();
    return items.docs;
  }

  // likesUp(String id) => ref.doc(id).update(...);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: FutureBuilder<List<QueryDocumentSnapshot<Post>>>(
          future: readData(),
          builder: (context, snapshot) {
            if (snapshot.hasData &&
                snapshot.connectionState == ConnectionState.done) {
              return ListView.builder(
                itemCount: snapshot.data!.length,
                itemBuilder: (context, index) => ListTile(
                  title: Text(snapshot.data![index].data().title),
                  subtitle: Text(snapshot.data![index].data().content),
                  trailing: IconButton(
                    icon: const Icon(Icons.favorite),
                    onPressed: (){},
                    // onPressed: () => likesUp(snapshot.data![index].id),
                  ),
                ),
              );
            }
            return const SizedBox();
          },
        ),
      ),
    );
  }
}

firestore에서 받아온 json 데이터를 가지고 데이터모델을 만들면 일반 객체로 접근이 가능하다.타입도 안전하게 지켜지고 , String key로 접근하다 실수하는 일도 없어진다.

그런데 모델이 많아지면 일일이 받아오는 것이 쉽지않다.

그래서 firestore 레퍼런스를 가져올때 withConverter 함수를 사용해서 JSON이 아닌 객체를 주고 받고 그 데이터 타입도 정해줄 수 있다.

var ref = FirebaseFirestore.instance.collection('post').withConverter(
	//firestore에서 JSON이 아닌 객체로 데이터를 넘겨줌
    fromFirestore: (snapshot, _) => Post.fromMap(snapshot.data()!),
     //firestore에 저장할 때 객체를 Json으로 변경해서 넘겨줌
    toFirestore: (data, _) => data.toMap(),
  );

이렇게하면 얻어온 데이터 타입은 JSON(Map<String,dynamic>이 아닌 Post 객체다. 이제 별도의 변환없이  firestore 문서에 바로 객체처럼 접근할 수 있다.

 

 

위의 제공된 코드의 주석을 처리하면 다음과 같이 구현이 가능하다. trailing의 IconButton을 클릭하면 해당 포스트의 좋아요 수가 +1만큼 올라간다. 주석을 해제하고, 코드를 알맞게 작성하시오.

FieldValue를 사용하여 해결할 것

 

위에 주석처리된 부분

 likesUp(String id) => ref.doc(id).update({'likes': FieldValue.increment(1)});

likes가 1씩 증가하도록 업데이트한다.

 

20230315_011929.mp4
0.11MB

 

[참고]

https://velog.io/@allegromoth/Flutter-%EC%95%B1%EA%B3%BC-Firebase-%EC%97%B0%EB%8F%99

플러터앱과 firebase연동 오류들...

https://engschool.tistory.com/160

withConverter