ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Flutter - 코딩마스터하기|Firebase Firestore 사용하기
    개발/Flutter 2021. 11. 11. 00:25
    반응형

    create firestore keys

    constants에 firestore_keys.dart 파일을 만들어 준다. 아래에 올려준 부분을 작성해준다. 여기서 COLLECTION은 firestroe에서 collection에 해당하는 부분이 될 것이고 KEY는 collection 안에 key value에서 key의 해당하는 부분이 될 것이다.

    그외에 강의는 다 어떻게 이렇게 선택하게 된건지 만드는 과정임.


    const COLLECTION_POSTS = 'Posts'; //COLLECTION은 firestore 의 collection부분
    const COLLECTION_USERS = 'Users';
    
    const KEY_USERSKEY ='user_key'; //KEY는 field의 key 값들
    const KEY_PROFILEIMG ='profile_img';
    const KEY_EMAIL ='email';
    const KEY_LIKEDPOSTS ='profile_img';
    const KEY_FOLLOWERS ='followers';
    const KEY_FOLLOWINGS ='followings';
    const KEY_MYPOSTS ='my_posts';
    const KEY_USERNAME ='username';
    
    const KEY_COMMENT ='comment';
    const KEY_COMMENTTIME ='commenttime';
    
    const KEY_POSTIMG ='postimg';
    const KEY_POSTURI ='posturi';
    const KEY_CAPTION ='caption';
    const KEY_LASTCOMMENT ='last_comment';
    const KEY_LASTCOMMENTOR ='last_commentor';
    const KEY_LASTCOMMENTTIME ='last_commenttime';
    const KEY_NUMOFLIKES ='num_of_likes';
    const KEY_NUMOFCOMMENTS ='num_of_comments';
    const KEY_POSTTIME ='post_time';

    create user model

    우선 user model 을 만들어 보자. 이해는 어려운 부분이라서 final 로 각 값들을 해주고 그것을 map으로 KEY오 ㅏ연결해주고 Snapshot를 써서 연결해준다고 생각하자.

    mldels 폴더에 firesotre 폴더를 하나 더 만들어 주고 그 안에 user_model.dart를 만들어 주면 된다.


    class UserModel {
      final String userKey;
      final String profileImg;
      final String email;
      final List<dynamic> myPosts;
      final int followers;
      final List<dynamic> likedPosts;
      final String username;
      final List<dynamic> followings;
      final DocumentReference reference; //firestore해서 데이터를 가져오면 해당 document 의 위치를 저장해주는 저장공간 데이터 타입
    
    
      UserModel.fromMap(Map<String, dynamic> map, this.userKey,{this.reference}) //fromMap은 Dart 내장 함수
      :profileImg = map[KEY_PROFILEIMG],
      username = map[KEY_USERNAME],
      email = map[KEY_EMAIL],
      likedPosts = map[KEY_LIKEDPOSTS],
      followers = map[KEY_FOLLOWERS],
      followings = map[KEY_FOLLOWINGS],
      myPosts = map[KEY_MYPOSTS];
    
      UserModel.fromSnapshot(DocumentSnapshot snapshot) // cloud firestore 함수
      : this.fromMap(
        snapshot.data,
        snapshot.documentID,
        reference : snapshot.reference
      );
    }

     


    create user model state

    유저 모델을 만들었으니 state를 만들어서 유저가 바뀌면 그 상태를 바꿔주는 부분을 만들어 보자. model 폴더에 user_model_state.dart 파일을 만들어주고 extends로 ChangeNotifier로 만들어 준다. 그리고 UserModel _userModel;을 해준 뒤 get 과 set을 만들어 준다 UserModel get userModel => _userModel로 get을 해주고  set userModel(UserModel userModel){}로 set을 만들어 준다. set 안에는 _userModel = userModel; 을 넣어줘서 바뀐 유저의 값을 넣어주고 notifyListeners();로 이 값을 가지고 있는 곳에 알려주면 된다.


    class UserModelState extends ChangeNotifier{
      UserModel _userModel;
    
      UserModel get userModel => _userModel;
    
      set userModel(UserModel userModel){
        _userModel = userModel;
        notifyListeners();
      }
    }

    데이터 주고 받아보기

    firebase에서 firestore를 만들어준다. 우선 test모드를 선택하고 만들어 주면 된다. 그리고 lib 폴더 안에 repo 폴더를 만들어 주고 user_network_repository.dart 파일을 만들어주고 여기에 firestore와 파일을 주고 받는 메소드를 만들어 줄 것이다. class 는 그냥 UserNetworkRepository로 만들어 준후 Future<void> sendData(){}와 void getData{}를 만들어 준다. 일단 주고 받는 것을 보이위한 코드를 만들어 보자. sendData에 return에 Firestore.instace를 사용한다. .collection()으로 user데이터 이므로 'Users'로 해주고 뒤에 .document()를 해준다. document의 안에는 우선 임의의 문자를 넣어준다. 그리고 그 뒤에 setData()로 값을 넣어줄 수 있다. ()안에 {key: value, key:value}형태로 넣어주면 된다. 우선 'email': 'testing@gmail.com', 'username': 'myUserName'를 넣어준다. 그리고 getData에서는 똑같은 collection과 document의 데이터를 빼와야 하므로 Firestore.instance.collection('Users').document('123123123')를 똑같이 해준다. 그리고 그 뒤에 get()을 해서 데이터를 가져온다. 그 뒤에 .then((docSnapshot=>print(docSnapshot.data));를 해줘서 우선은 print를 하게 해준다. 그리고 class 밖에 이 것들을 쓸 수 있게 하기 위해서 UserNetworkRepository userNetworkRepository = UserNetworkRepository();를 넣어 준다. 그리고 feed_screen에 가서 상단 우측에 2개의 버튼에 각각 userNetworkRepository.sendData(); 와 userNetworkRepository.getData();를 해준뒤 실행하면 정상 작동하는것을 알 수 있다.


    class UserNetworkRepository {
      Future<void> sendData() {
        return Firestore.instance
            .collection('Users')
            .document('123123123')
            .setData({'email': 'testing@gmail.com', 'username': 'myUserName'});
      }
    
      void getData() {
        Firestore.instance
            .collection('Users')
            .document('123123123')
            .get()
            .then((docSnapshot) => print(docSnapshot.data));
      }
    }
    
    UserNetworkRepository userNetworkRepository = UserNetworkRepository();

    create user data from sign up

    가입을 하면서 데이터를 넣어보자. 우선 테스트로 넣었던 collection을 삭제하자. 그리고 다음의 메소드로 변경해준다.


    class UserNetworkRepository {
      Future<void> attemptCreateUser({String userKey, String email}) async {
        final DocumentReference userRef = Firestore.instance
            .collection(COLLECTION_USERS)
            .document(userKey); //document 위치
        DocumentSnapshot snapshot = await userRef.get(); // 해당 위치에서 데이터를 가져와 보는것
        if (!snapshot.exists) {
          //exists는 존재하지 않는다.
          return await userRef.setData(UserModel.getMapForCreateUser(email));
        }
      }
    }

    해당 collection 연결 부분과 그 위치의 데이터를 가져오는 것, 그리고 snapshot가 데이터가 없지 않다면 setData 해주는 부분이다. 그리고 firebase_auth_state에가서 registerUser에서 다음 부분을 추가해 준다.


        FirebaseUser firebaseUser = authResult.user;
        if (firebaseUser == null) {
          SnackBar snackBar = SnackBar(
            content: Text("Please try again later!"),
          );
          Scaffold.of(context).showSnackBar(snackBar);
        } else {
          userNetworkRepository.attemptCreateUser(
              userKey: firebaseUser.uid, email: firebaseUser.email);
        }

    상단에 _firebaseAuth.createUserWithEmailAndPassword를 하는 부분을 앞에 AuthResult authResult = await로 추가해줘서 값을 저장해둔다(async도 추가). 그 후 그 값을 FirebaseUser firebaseUser = authResult.user; 에 저장해서 db에 저장할때 uid와 email값을 가져오기 위함이다. 페이스 북이 아닌 이메일로 가입해보면 정상적으로 디비에 저장되는것을 알 수 있다.(왜인지 모르겠으나 페이스북은 db에 추가가 안됨)

     

    create user model stream

    데이터를 받아오는 부분을 추가해 보자. Stream을 통해서 받아올 것이다. .get은 처음에 한번만 Document로 가져오는데 .snapshot는 처음에 한번 받아오는것은 똑같지만 변할때마다도 받아온다. snapshot이 Stream을 반환하므로 Stream<UserModel> getUserModelStream(String userKey){}로 메소드를 만들어 준다. 그 안에 바로 retrun에 Firestore.instance.collection(COLLECTION_USERS).document(userKey)를 넣어서 계정의 document까지 간뒤.snapshots()으로 받아온다. 그리고 이 데이터를 원하는 형태로 받기 위해 .transform() 을 하는데 ()안에 넣어야 할 부분을 만들어 보자. repo 폴더에 helper 폴더를 추가해주고 그안에 transformers.dart를 만들어 준다. 그리고 그안에 받아오는 부분을 만들 것이다. class Transformers{}를 해주고 그안에 fianl toUser 를 해준다. = StreamTransformer<DocumentSnapshot, Usermodel>을 해줘서 DocumentSnapshot를 Usermodel로 변경시켜줄 것이다. <>뒤에 .fromHandlers()를 해주고()안에 handleData: (snapshot,sink) async{}를 해준다. {}안에 sink.add(UserModel.fromSnapshot(snapshot));를 해주면 된다. 그리고 transform(toUser)를 해주면 된다. 그리고  transform을 사용하기 위해 class 뒤에 with Transformers 를 붙여준다. 그리고 firebase_auth_state에서 그냥 FirebaseUser firebaseUser라고 했던 부분들을 _firebaseUser라고 변경해준다. main에서는 이를 위해 MultiProvider를 사용해야 하므로 MaterialApp을 MultiProvider로 감싸주고 provider 옵션에 ChangeNotifierProvider<FirebaseAuthState>.value( value: _firebaseAuthState,) 이부분을 넣어준다. 그리고 그 밑에 ChangeNotifierProvider<UserModelState>( create: (_) => UserModelState(), ), 를 추가해줘서 UserModelState도 같이 쓰이게 해준다. 이제 profile_body로 가서 id가 들어 가는 부분을 Provider.of<UserModelState>(context).userModel.username, 으로 변경해준다. 이때 context를 써야 하므로 메소드에서 Buildcontext를 받아온다. 그리고 main에서 signin일때 userNetworkRepository .getUserModelStream(firebaseAuthState.firebasUser.uid) .listen((userModel) { Provider.of<UserModelState>(context, listen: false) .userModel = userModel; });를 추가해서 유저에 대한 데이터 변경시 가져와서 값을 변환 시켜주도록 하면 된다.

    반응형

    댓글

Designed by Tistory.