Firebase Firestore 및 인증을 사용하는 Svelte 3의 RxFire

RxFire은 Firebase Developer Advocate인 에 의해 만들어졌습니다. Firebase Blog은 2018년 9월에 RxFire를 도입했지만 Svelte 3Firebase 모두로 시작하는 초보자에게 좋은 참고 자료가 될 것이라고 생각했습니다. Angular 배경에서 온 사람들에게는 RxJS에 익숙할 것입니다 및 Angularfire2 패키지. 내 경험상 모든 크기의 애플리케이션에서 Angular를 사용하려면 RxJS를 배워야 한다는 것을 알고 있습니다. 배우기 가장 어려운 부분 중 하나일 수 있지만 RxJS 작동 방식에 대한 환상적인 튜토리얼과 사이트가 많이 있습니다. 제가 가장 좋아하는 것 중 일부는

Svelte 3을 처음 사용하는 경우 확인하십시오.

예시



아래 예에서는 최종 React 애플리케이션이 어떻게 작동하는지 빠른 미리보기 osf를 보여줍니다. 보시다시피 발생하는 필수적인 4단계가 있습니다.
  • 로그인
  • 고양이 팩트 추가
  • 목록에 추가된 고양이 사실 표시
  • 로그아웃

  • 설정



    nodejs와 함께 번들로 제공되는 NPM이 필요합니다. 또한 npx은 git에서 제공하는 템플릿을 사용하는 것이 가장 쉽습니다.
    npx degit sveltejs/template rxfire-svelte cd rxfire/svelte
    또한 자체 Firebase 프로젝트를 생성하고 Firestore 데이터베이스를 초기화해야 합니다. 엄격 모드를 사용하여 생성하세요. Example rules ;

    최종 앱 구조







    종속성 설치



    rxfire , firebaserxjs 이 필요합니다.

    npm i rxfire firebase rxjs

    Firebase.js 만들기



    Firebase.js는 기본 Firebase 파일이 될 것이며 Firebase 인스턴스화를 포함하여 Firebase 애플리케이션용 도구를 포함할 것입니다. 이 파일에는 auth 및 firestore 도우미 함수 모두에 대한 rxfire가 포함되어 있습니다.Firebase.js

    ```일반 텍스트
    "firebase/auth"가져오기;
    "firebase/firestore"가져오기;
    "firebase/app"에서 파이어베이스 가져오기;
    "rxfire/auth"에서 { authState } 가져오기;
    "rxfire/firestore"에서 가져오기 { collectionData };
    "rxjs/operators"에서 { 필터 } 가져오기;
    const 앱 = firebase.initializeApp({
    /* 여기에 구성 배치 */
    });
    const firestore = firebase.firestore(app);//파이어스토어 초기화
    const auth = firebase.auth(앱);//Firebase 인증 초기화
    const loggingIn$ = authState(auth).pipe(filter(user => !!user));//Observable은 사용자가 로그인한 경우에만 반환됩니다.
    내보내기 { 앱, 인증, firestore, collectionData, logIn$ };
    기본 파이어베이스 내보내기;

    
    
    
    > 
    
        You can skip the Instructions part of the lesson if you are already familiar with Svelte 3.
    
    ## Simple Initial Component
    
    ### Remove App.svelte and replace it with the following
    
    You can basically think of a .svelte file equal to an html file. There are a few things to note here, any styles are scoped to the current component by default, in order to get styles outside of this you can place them within something like `:global(div.flex-row)`. However (maybe best practice), I found it easier to move these from App.svelte over to `/public/global.css`;App.svelte
    
    
    
    ```plain text
    <script>
        import Instructions from './components/Instructions.svelte';
        import SignIn from './components/Signin.svelte';
        import AddCat from './components/AddCat.svelte';
        import ListCatFacts from './components/ListCatFacts.svelte';
        import { loggedIn$ } from './Firebase.js'
        /\* Make something more observable \*/
        const user = loggedIn$;
    </script>
    <style>
        /\* :global(div.flex-row){ display: flex; justify-content: center; flex-flow: row wrap; } :global(div.flex-column){ display: flex; justify-content: center; flex-flow: column; } .max-800{ max-width: 800px; } \*/
    </style>
    <div class="flex-row">
        <div class="flex-column">
            <Instructions />
        </div>
    </div>
    
    

    지침 만들기.svelte



    이것은 no props 를 사용하는 매우 간단한 Svelte 구성 요소입니다. 바로 html.components/Instructions.svelte를 반환합니다.

    ```일반 텍스트

     <img src="https://res.cloudinary.com/ajonp/image/upload/w%5C_500/v1556553295/ajonp-ajonp-com/18-rxfire-svelte-cats/RxFire%5C_Svelt.webp" alt="rxfire for cats"> 
    
        <p> In this example we will use RxFire to Observe the Cat Facts that we add to our Firestore Database. </p> <a href="https://github.com/AJONPLLC/rxfire-react-cats">
            https://github.com/AJONPLLC/rxfire-react-cats </a>
        <ol>
            <li> Sign In <ul>
                    <li>Uses Google Auth for Firebase</li>
                    <li>Found in App.svelte</li>
                </ul>
            </li>
            <li> Add Cat Fact <ul>
                    <li>This will use an API and Insert the facts into Firestore</li>
                    <li>Found in components/AddCat.svelte</li>
                </ul>
            </li>
            <li> Firestore collection <ul>
                    <li>Observing catfacts for changes, heart eyes are your facts</li>
                    <li>Found in components/ListCatFacts.svelte</li>
                </ul>
            </li>
            <li> Sign Out <ul>
                    <li>Observe that user is removed</li>
                </ul>
            </li>
        </ol>
    

    
    
    
    ## Update collection catfacts
    
    ### Create AddCat.svelte
    
    The first button that we are going to add is simple enough it calls an API and pushes the data returned into a firestore collection as a new document. I always like to work from top down, so first lets import AddCat.svelte into our App.svelte.
    
    ### Update App.svelte
    
    App.svelte
    
    
    
    ```plain text
    ... import AddCat from './components/AddCat'; ... <SignIn user={user} /> ...
    
    


    이제 첫 번째 prop을 AddCat 에 전달할 것입니다. 이것은 변수를 선언하고 전달함으로써 간단하게 수행됩니다. 이 경우에는 const user = loggedIn$ 를 사용합니다. 이것이 필요한지, 아마 아닐지 모르지만 소품을 전달하는 것을 보여주고 싶었습니다. 이상적으로는 Firebase.js에서 이것을 가져올 수 있습니다. 자식에 유의하십시오. 그런 다음 export let user;를 정의하여 이 소품에 액세스할 수 있습니다. addCatFact 함수는 다음을 호출합니다. https://cat-fact.herokuapp.com 에서 임의의 단일 고양이 팩트를 반환하는 API입니다. CORS 때문에 프록시를 통해 전달해야 하지만 값을 다시 받는 것을 볼 수 있습니다. 그런 다음 javascriptdestructuring assignment를 사용하여 객체에 우리catFactDate를 추가하여 새 객체를 만듭니다. 이렇게 하면 나중에 목록의 팩트를 내림차순으로 정렬할 수 있습니다. 임의의 고양이 팩트를 firestore에 추가하고 객체에 catFactDate를 추가합니다. 이렇게 하면 나중에 목록의 사실을 내림차순으로 정렬할 수 있습니다. 여기서 특별히 주의해야 할 사항은 다음과 같습니다.
  • if - If 블록은 표준일 뿐이며 예상할 수 있는 경우

  • $user - Subscriptions 각도에서 온 경우 이것은 비동기 파이프와 같습니다.
  • on:click={addCatFact - Component Events 이것은 일반적으로 html 구성 요소에서 발견되는 이벤트와 유사하지만 여기서는 단지 곱슬머리로 둘러싸서 함수addCatFact를 전달합니다.

  • ```일반 텍스트

    import { firestore } from '../Firebase';
    import catFacts from '../random.js';
    export let user;
    const addCatFact = async () =&gt; {
        try {
            /\* Gave up on the API working!!! \*/
            const value = catFacts\[Math.floor(Math.random() \* catFacts.length)\];
            await firestore.collection('catfacts').add({ ...value, catFactDate: new Date() });
        }
        catch (error) { console.error(error); }
    };
    
    
    
    {#if $user}  2. Add Cat Fact  {/if} 
    

    
    
    
    Now if you try this right now it should fail with this alert
    
    ![](https://media.codingcat.dev/image/upload/v1657636585/main-codingcatdev-photo/7868ceef-45bb-4114-b3d3-bea7dbbfa2da.jpg)
    
    This is expected as our firestore.rules are set to strict mode, we will add those after we get through our authentication section next.You may also notice in the console (and on the screen fact jumps in and out) that firebase actually adds to our array, until failing on the backend. This is done on purpose as it gives us the fast UI that we expect while still maintaining the data integrity.
    
    ## Add Firebase Authentication
    
    ### Update App.svelte
    
    In the `SignIn` component we will again use props, we will pass the user state.App.svelte
    
    ` ... import SignIn from './components/Signin.svelte'; ...  ...  ...`
    
    
    
    ```plain text
    
      import firebase, { app } from '../Firebase'; /\* this is like props \*/ export let user; const signIn = () =&gt; { const authProvider = new firebase.auth.GoogleAuthProvider(); app.auth().signInWithPopup(authProvider); }; const signOut = async () =&gt; { await firebase.auth().signOut(); };
    
    
      {#if $user}
      <h1>
        Welcome {$user.email}
        4. Sign Out
      </h1>
      {:else}
      1. Sign In {/if}
    
    <div class="highlight"><pre class="highlight plaintext"><code>
    
    
    ## Update AddCat to include user uid
    
    ### Pass user to AddCat
    
    Update our main app to pass the user prop.App.svelte
    
    `&lt;AddCat user={user} /&gt;`
    
    Now we can use this to include with our data going to firestore. AddCat.svelte
    
    As well as whether or not to show the Add Cat Fact button, we check to see if the user exists. This button should only show when a user is signed in.
    
    
    
    ```plain text
    &lt;div class="flex-column"&gt; {#if $user} &lt;button className="myButton" on:click="{addCatFact}"&gt; 2. Add Cat Fact &lt;/button&gt; {/if} &lt;/div&gt;
    
    </code></pre></div>
    <p></p>
    <h2>
      <a name="update-firestorerules" href="#update-firestorerules">
      </a>
      Update firestore.rules
    </h2>
    
    <p></p>
    
    <p>```plain text<br>
    service cloud.firestore {<br>
        match /databases/{database}/documents {<br>
            // LockDown All<br>
            match /{document=**} {<br>
                allow read: if false; allow write: if false;<br>
            }<br>
            // User<br>
            match /users/{userId} {<br>
                allow read: if false;<br>
                allow write: if request.resource.id == request.auth.uid;<br>
            }<br>
            // CatFacts<br>
            match /catfacts/{catFactId} {<br>
                allow read: if true;<br>
                allow write: if request.auth.uid != null &amp;&amp; request.resource.data.uid == request.auth.uid;<br>
            }<br>
        }<br>
    }</p>
    <div class="highlight"><pre class="highlight plaintext"><code>
    
    
    ## Create List of Cat Facts
    
    ### Create ListCatFacts
    
    This is probably the most important part of `RxFire` it will return an Observable that you can subscribe to for all changes to a collection by using the function `collectionData` which takes the collection as paramater as well as an option id to create, in our case we pass `catFactsRef.orderBy('catFactDate', 'desc')` and `'catFactId'`.Now we can just use a map to iterate on each catFact, whenever the Observable updates the current `catFact` state the array is updated and we can show the full list update using `{#each $catFacts as catFact}` then if you are the owner of the fact you get catheart eyes using a if block.
    
    
    
    ```plain text
    &lt;script&gt;
      import { firestore } from "../Firebase";
      import catFacts from "../random.js";
      export let user;
      const addCatFact = async () =&gt; {
        try {
          /\* Gave up on the API working!!! \*/ const value =
            catFacts\[Math.floor(Math.random() \* catFacts.length)\];
          await firestore
            .collection("catfacts")
            .add({ ...value, catFactDate: new Date() });
        } catch (error) {
          console.error(error);
        }
      };
    &lt;/script&gt;
    &lt;div class="flex-column"&gt;
      {#if $user}
      &lt;button className="myButton" on:click="{addCatFact}"&gt;2. Add Cat Fact&lt;/button&gt;
      {/if}
    &lt;/div&gt;
    
    </code></pre></div>
    <p></p>
    

    좋은 웹페이지 즐겨찾기