React

React: Supabase

고래고래00 2024. 5. 22. 17:54

01. BaaS

BaaS란

Backend as a System

웹과 모바일 앱 개발을 쉽고 빠르게 할 수 있게 도와주는 클라우드 기반 백엔드 서비스

BaaS를 이용하면 프론트엔드 개발에 더 집중 가능

 

웹 애플리케이션의 필수 구성요소 3가지

  1. 프론트엔드 : 사용자가 보고 상호작용하는 면, 웹 사이트의 모든 시각적 요소를 담당
  2. 백엔드 : 서버 측에서 데이터 처리, 사용자 관리, 로직 처리 등을 맡음, 보이지 않는 곳에서 많은 일
  3. 데이터베이스 : 사용자 정보, 게시글 등 모든 데이터를 저장하고 필요할 때 불러오는 저장소

BaaS의 필요성 : 프론드엔드 개발에만 집중가능

BaaS의 예시 : Firebase, Parse, AWS Amplify, Supabase .. 

 

BaaS 장단점

장점

  • 개발 속도 향상 : BaaS를 쓰면 백엔드를 직접 만들 필요없음
    이미 준비된 기능들을 바로 사용할 수 있으니, 개발 시간을 크게 단축

  • 유지보수 간편 : 서버 운영이나 백엔드 시스템 관리에 대한 걱정이 줄어들어, 유지보수가 훨씬 편함

  • 자동 확장 : 사용자가 늘어나도 서비스가 자동으로 스케일 업 => 서버 부하 걱정 없이 안정적인 서비스를 제공

단점

  • 유연성 부족 : 표준화된 기능 외의 특별한 요구사항을 충족시키기 어려울 수 있음
  • 비용 예측 어려움 : 사용량이 많아질수록 비용도 늘어남

  • 플랫폼 의존성 : 한 플랫폼에 의존하게 되면 나중에 다른 서비스로 이전하기 어려워질 수 있음

02. Supabase 

Supabase란

Supabase는 PostgreSQL을 기반으로 하는 오픈 소스 BaaS 플랫폼

관계형(SQL) 데이터베이스를 사용 

실시간으로 데이터 변화를 감지하고 반응

=> 데이터베이스가 업데이트가 필요할 때마다 UI가 자동으로 반응해서 변경사항을 보여줌

Supabase 필요성 (firebase와 비교)

관계형 데이터 모델과 실무적인 역량

실무에서는 데이터의 일관성과 정확성이 매우 중요 => 많은 기업에서 관계형 데이터베이스 사용

관계형 데이터베이스에서 데이터를 저장하는 방법은 엑셀과 매우 흡사

 

실시간 기능의 실무적 적용

Firebase도 실시간 데이터베이스 기능을 제공, Supabase는 이 기능을 관계형 데이터베이스의 장점과 결합하여 제공

실시간 데이터 처리가 중요한 주식 거래 플랫폼, 실시간 대시보드, 협업 도구 등에 유용

 

확장성, 보안, 오픈소스 커뮤니티 등의 장점

React에서 사용

설치 및 세팅

 

설치

터미널

yarn add @supabase/supabase-js

 

Supabase 클라이언트 초기화 코드 작성

1. Supabase 홈페이지 접속

https://supabase.com/

 

Supabase | The Open Source Firebase Alternative

Build production-grade applications with a Postgres database, Authentication, instant APIs, Realtime, Functions, Storage and Vector embeddings. Start for free.

supabase.com

2. 로그인 후 Start your project에 들어가 new project 생성

3. Table Editor에서 new table 생성

4. 열을 필요한 만큼 추가 후 데이터 명과 타입을 지정 후 저장

5. 코드로 돌아와 src 폴더에 supabaseClient.js 파일 생성 후 API 키와 URL로 데이터베이스 연결

 

supabaseClient.js

import { createClient } from "@supabase/supabase-js";

const SUPABASE_PROJECT_URL = "YOUR_SUPABASE_URL"; // supabase URL

const SUPABASE_ANON_KEY = "YOUR_SUPABASE_KEY"; // supabase API KEY

const supabase = createClient(SUPABASE_PROJECT_URL, SUPABASE_ANON_KEY);
export default supabase;

 

6. 데이터베이스 읽기

supabase데이터베이스에 만들어뒀던 테이블에 row를 inset해 데이터 추가

데이터베이스에서 데이터를 읽어올 FetchData 컴포넌트 생성 및 코드 작성

FetchData.jsx

import React, { useEffect } from 'react'
import supabase from '../supabaseClient'

const FetchData = () => {
    // 데이터베이스를 읽어오는 역할
    // 컴포넌트가 mount된 후에 어떤 동작을 수행 => useEffect 및 의존성 배열을 빈 배열
    // 비동기 작업이므로 async - await 사용
    useEffect(() => {
        const fetchData = async () => {
            const { data, error } = await supabase.from("NBCAMP_SAMPLE").select("*");
            if (error) {
                console.log("error => ", error);
            } else {
                console.log("data => ", data);
            }
        };

        fetchData();
    }, [])

    return (
        <div>FetchData</div>
    )
}

export default FetchData

App.jsx에 연결하고 데이터를 잘 가져오는지 콘솔창 확인

데이터를 잘 가져오는 것을 확인 가능

가져온 데이터를 화면에 나타내기

FetchData.jsx

import React, { useEffect, useState } from 'react'
import supabase from '../supabaseClient'

const FetchData = () => {
    // 컴포넌트를 뿌려주기 위해 state
    const [users, setUsers] = useState([]);

    // 데이터베이스를 읽어오는 역할
    // 컴포넌트가 mount된 후에 어떤 동작을 수행 => useEffect 및 의존성 배열을 빈 배열
    // 비동기 작업이므로 async - await 사용
    useEffect(() => {
        const fetchData = async () => {
            const { data, error } = await supabase.from("NBCAMP_SAMPLE").select("*");
            if (error) {
                console.log("error => ", error);
            } else {
                console.log("data => ", data);
                setUsers(data); // user 안에 DB로부터 받아온 값을 저장
            }
        };

        fetchData();
    }, [])

    return (
        <div>
            <h3>유저정보</h3>
            {
                users.map(user => {
                    return (
                        <div key={user.id}>
                            <h5>{user.name}</h5>
                            <h5>{user.age}</h5>
                            <h5>{user.address}</h5>
                        </div>
                    );
                })
            }
        </div>
    )
}

export default FetchData

supabase의 테이블에 새로운 값을 추가해보고 화면에 나오는지 확인

DB에 데이터를 추가하니 화면에 잘 나타나는 것을 확인 가능

 

7. 코드상에서 데이터 추가하기

데이터를 추가하는 로직을 가진 AddData 컴포넌트 생성 및 코드 작성

AddData 컴포넌트에서는 이름, 나이, 주소를 가진 데이터가 입력되어야 함

AddData.jsx

import React, { useState } from 'react'
import supabase from '../supabaseClient';

const AddData = () => {
    // 이름, 나이, 주소 3개의 state 필요
    const [name, setName] = useState("");
    const [age, setAge] = useState(0);
    const [address, setAddress] = useState("");

    // 데이터를 추가하는 로직
    // 가져오는 것은 select, 데이터를 추가하는 것은 insert
    // 이름, 나이, 주소를 가진 객체형태로 DB에 추가
    const handleAdd = async () => {
        const { data, error } = await supabase.from("NBCAMP_SAMPLE").insert({
            name,
            age,
            address,
        });
        if (error) {
            console.log("error => ", error);
        } else {
            alert("데이터가 정삭적으로 입력됐습니다.");
            console.log("data => ", data);
        }
    };

    return (
        <div>
            <h2>데이터 추가 로직</h2>
            <div>
                이름 : <input type='text' value={name} onChange={(e) => {
                    setName(e.target.value);
                }} />
            </div>
            <div>
                나이 : <input type='text' value={age} onChange={(e) => {
                    setAge(e.target.value);
                }} />
            </div>
            <div>
                주소 : <input type='text' value={address} onChange={(e) => {
                    setAddress(e.target.value);
                }} />
            </div>
            <button onClick={handleAdd}>등록</button>

        </div>
    )
}

export default AddData

DB에 데이터를 추가하고 추가한 데이터가 화면에 잘 나타나는지 확인

인풋에 값을 입력하고 등록버튼을 누르면 DB에 추가되고 새로고침하면 화면에 잘 나타나는 것을 확인 가능

 

8. 데이터 수정하기

UpdateData 컴포넌트 생성

UpdateData에서는 id를 입력받아서 해당되는 데이터의 주소를 바꿔줄 것

(FetchData 컴포넌트에서 id도 화면에 나타나도록 코드 수정)

UpdateData 컴포넌트에서는 어떤 id에 대한 값을 수정할지, 그 주소는 어떻게 바뀔지를 input으로 받을 것

UpdateData.jsx

import React, { useState } from 'react'
import supabase from '../supabaseClient';

const UpdateData = () => {
    // id와 주소를 state로
    const [targetId, setTargetId] = useState(0);
    const [address, setAddress] = useState("");

    // 데이터 수정 로직
    // 데이터 수정은 update
    const handleChange = async () => {
        const { error } = await supabase.from("NBCAMP_SAMPLE").update({
            address,
        }).eq('id', targetId); // id가 targetId랑 동일한 것을 update

        if (error) {
            console.log("error => ", error);
        }
    }

    return (
        <div style={{
            border: "1px solid blue",
        }}>
            <h2>데이터 수정 로직</h2>
            아이디: <input type='number' value={targetId} onChange={(e) => {
                setTargetId(e.target.value);
            }} />
            <br />
            수정주소: <input type='text' value={address} onChange={(e) => {
                setAddress(e.target.value);
            }} />
            <button onClick={handleChange}>수정</button>
        </div>
    )
}

export default UpdateData

App.jsx에 연결한 후 id와 수정할 주소를 입력하고 버튼을 누르면 해당하는 id의 주소가 변경되는지 확인

id와 수정주소를 입력하고 버튼을 누른 후 새로고침하면 해당하는 id의 주소가 잘 변경되는 것을 확인 가능

 

9. 데이터 삭제하기

데이터를 삭제하는 컴포넌트 DeleteData를 생성

DeleteData 컴포넌트는 UpdateData 컴포넌트와 유사

id를 입력받아 해당하는 id의 정보를 DB에서 삭제

DeleteData.jsx

import React, { useState } from 'react'
import supabase from '../supabaseClient';

const DeleteData = () => {
    // 데이터 삭제는 수정과 비슷하므로 수정 로직을 복사 후 필요한 부분 수정
    const [targetId, setTargetId] = useState(0);

    // 데이터 삭제 로직
    // 데이터 삭제는 delete
    const handleDelete = async () => {
        const { error } = await supabase
            .from("NBCAMP_SAMPLE")
            .delete()
            .eq('id', targetId); // id가 targetId랑 동일한 것을 delete

        if (error) {
            console.log("error => ", error);
        }
        else {
            alert("삭제가 완료되었습니다.");
        }
    }
    return (
        <div style={{
            border: "1px solid blue",
        }}>
            <h2>데이터 삭제 로직</h2>
            아이디: <input type='number' value={targetId} onChange={(e) => {
                setTargetId(e.target.value);
            }} />
            <button onClick={handleDelete}>삭제</button>
        </div>
    )
}

export default DeleteData

삭제하려는 데이터의 id를 input에 입력하고 삭제 버튼을 눌렀을 때, 해당하는 id의 데이터가 삭제되는지 확인

2를 입력하고 삭제버튼을 눌렀을 때

id가 2인 데이터가 DB에서 삭제되고 새로고침했을 때 화면에서 제거되는 것을 확인가능