Web 강의/트위터 클론코딩

[노마드/트위터 클론코딩] Nwitter

sumiin 2022. 3. 23. 12:13
반응형
SMALL

FireBase

아주 빠르게 무언가를 시작할 수 있도록 도와줌(아이디어를 구상중일 때 많이 사용, 비즈니스 용으로는 많이 사용하지 않음)

Securing the Keys

  • react app에서 환경변수를 설정하려면REACT_APP_으로 시작해야함
  • key들을 .env에 저장
  • <.env>에 저장하는 이유?
    • <.gitignore> file에 .env를 작성한다면 .env에 쓴 키들은 git에 올라가지 않음 -> 보안상의 이유로 key,URL 들은 비공개
    • 하지만 React application을 실행하면 서비스를 위해 빌드하고 웹사이트를 띄우면 create-react-app은 이 코드들을 실제 값들로 변환시켜 공개됨(단순히 github에 key를 업로드하지 않기 위함)

Router Setup

  • Fragment (<> </>): 많은 요소들을 render하고 싶을 때 사용(부모 요소가 없을 때 )

Authentication

  • firebase.auth() : Authentication 기능을 제공

Login

  • onChange : 값이 바뀔때마다 사용
    • argument인 event는 무슨 일이 일어났는지 확인해줌(target은 변경이 일어난 부분)
    • input을 변경할 때마다 onchange function이 일어남 (input에서 value 받아옴)
  • hooks를 이용해 상태 체크와 value 넣어주기 위해 사용
  • createUserWithEmailAndPasswordsignInWithEmailAndPassword를 이용해 로그인
  • setPersistence : 사용자를 어떻게 기억할 것인지 선택하도록 도와줌
    • default로 local
    • local : 브라우저를 닫더라도 사용자 정보는 기억될 것이라는 의미
    • session : 탭이 열려있는 동안에는 사용자 정보를 기억할 것이라는 의미
    • none : 유저정보를 기억하지 않는 것
  • onAuthStateChanged : (evnt listener) 유저 상태에 변화가 있을 때 변화를 알아차림
  • signWithPopup : provider를 만들고 provider로 로그인

LogOut

  • const onLogOutClick=()=>authService.signOut();: profile에서 logout 하는 기능 만들어줌
  • 로그아웃했을 때 "/"로 이동하는 두가지 방법
    1. <Redirect from="*" to="/" /> 을 통해 "/" 이외의 다른 루트일 경우 "/"로 가도록 설정 (in router.js)
    2. const history=useHistory(); history.push("/");를 이용해 onLogiytClick 눌렀을 때 로그아웃 되도록 설정 (in Profile.js)

Form

  • const {taget:{value},}=event == event.target.value 를 통해 input에서 받은 value를 set함

Database Set up

  • Cloud Firestore의 database는 NoSQL database

    • collection (폴더와 같음) -> dociments의 그룹
    • Document (컴퓨터에 있는 문서와 같은 텍스트)
    • 하나의 database는 collection들을 가지고 있고 collection은 docment들을 가지고 있음
  • dbService.collection("nweets").add(); : "nweets"라는 collection에 document ID를 자동으로 부여하며 새로운 document 추가

    • firebase.js에 firestore을 dbservice로 export한 후 , home.js에서 import 해서 사용
  • const dbNweets=await dbService.collection("nweets").get();: "nweets"라는 collection의 documnets get

    • dbNweets는 QueryDocumentSnapshot 형태이므로 dbNweets.forEach(document=> console.log(document.data()))를 이용해야 document들 확인 가능
  • setNweets([prev=>document.data(), ...prev]); : set을 쓰는 함수에서 값 대신에 함수를 전달할 수 있음 -> 만약 함수를 전달하면 리액트는 이전 값에 접근할 수 있게 해줌

    • dbNweets에 있는 모든 document에 대해 setNweets에서 함수를 사용하고 있는데 배열을 리턴, 이 배열에서 첫 번째 요소는 가장 최근 documet이고, 그 뒤로 이전 documet를 붙임

    • ...: spread attribute 기능 -> 데이터를 가져와서 풀어냄

      const [nweets,setNweets]=useState([]);
      const getNweets=async()=>{
      const dbNweets=await dbService.collection("nweets").get();
        dbNweets.forEach((document)=>{
            //dbNweets에 있는 모든 document에 대해 setNweets에서 함수를 사용하고 있는데 배열을 리턴, 이 배열에서 첫 번째 요소는 가장 최근 documet이고, 그 뒤로 이전 documet를 붙임  
            const nweetObject={
                ...document.data(),//...: spread attribute 기능 -> 데이터를 가져와서 풀어냄
                id:document.id,
      
            };
            setNweets(prev=>[nweetObject, ...prev]);//set을 쓰는 함수에서 값 대신에 함수를 전달할 수 있음 -> 만약 함수를 전달하면 리액트는 이전 값에 접근할 수 있게 해줌 
        });
        /*dbNweets는 QueryDocumentSnapshot 형태이므로 
        dbNweets.forEach(document=> console.log(document.data()))를 이용해야
        document들 확인 가능 
        */
      };
      useEffect(()=>{
        getNweets();
      },[]);
  • snapshot 이용

    • getNweets로 documents를 얻는 방식은 오래된 방식이고 snapshot을 이용하면 편리
    • snapshot은 실시간으로 전달됨
    • 지우거나 업데이트 등 무언가를 하면 바로 실행되는 함수
      useEffect(()=>{
        dbService.collection("nweets").onSnapshot(snapshot=>{
            const nweetArray=snapshot.docs.map(doc =>({id:doc.id, ...doc.data(),}));
            setNweets(nweetArray);
        })
      },[]);

Delete and Edit

  • dbService.doc(nweets/${nweetObj.id}).delete(); 을 이용해서 nweets 삭제
  • dbService.doc(nweets/${nweetObj.id}).update({text:newNweet});을 이용해서 text edit
  • storageService.refFromURL(nweetObj.attachmentUrl).delete();을 이용해 delete photo

Image

  • FileReader API 이용
    const onFileChange=(event)=>{
          const {target:{files},}=event;//event가 target안의 files 가리킴
          const theFile=files[0];
          const reader=new FileReader();
          reader.onloadend=(finishedEvent)=>{//event listner : 파일 로딩이 끝날 때 finishedEvent가짐             const {currentTarget:{result},}=finishedEvent;
              setAttachment(result)
          };
          reader.readAsDataURL(theFile);
      };
    const onClearAttachment =()=>setAttachment(null); //사진 clear시킴

Uploading

  • reference: Google Cloud Storage object에 대한 참조를 나타냄
    • child: 이 reference로부터 관련된 path로 reference를 반환
    • uuid : 어떤 특별한 식별자를 랜덤으로 생성해줌
    • storageService.ref().child(${userObj.uid}/${uuidv4()}); :파일에 대한 reference
      • 사진에 대한 아이디 생성해주기 위해 uuid 사용

Get My Nweets

const getMyNweets= async()=>{
        const nweets=await dbService.collection("nweets").where("creatorId","==",userObj.uid).get(); //where은 필터링 하는 방법 표기 
        console.log(nweets.docs.map(doc=>doc.data()))
    }
  • where을 통해 필터링하는 기준을 만들어 creatorId와 userObj.id가 같은 경우에만 nweets에 들어가는 것을 알 수 있음

Update Profile

  • profile을 변경해서 setUserObj를 하더라도 user은 방대한 양을 차지하므로 react에서 바로 rendering 안될 수도 있음
  • 해결 방법
    1. userObj에서 이용하는 객체만을 전달해줌 (이 방법 선호)
      setUserObj({//user를 저장해놓음 (user은 방대한 양을 차지하므로 이용하려는 객체들만 가져옴)
       displayName:user.displayName,
       uid:user.uid,
       updateProfile:(args)=>user.updateProfile(args),
      });
    2. Object.assign({},user)) 이용
      • 빈 object와 source 필요 -> 빈 object안에 source인 user의 사본이 새 object의 형태로 생성하여 react가 rendering됨
      • setUserObj(Object.assign({},user)));

Deploying (배포)

  1. pacjage.json에 "homepage": "https://suminRoh.github.io/nwitter" 추가
  2. npm i gh-pages
  3. package.json의 scripts에 "predeploy":"npm run build","deploy":"gh-pages -d build" 추가
  4. npm run deploy
  5. homepage url로 들어가기

API Keys Security

반응형
LIST