관리 메뉴

Dev Blog

How to use Real-time DB of Firebase 본문

Web Development/General Tech Knowledges

How to use Real-time DB of Firebase

Nomad Kim 2021. 4. 20. 00:49
  • How to do initial setting
  • Structure of Database
  • How to make CRUD function
  • Efficient State management
  • How to make table

 

How to do initial setting(how to find database)

Creates and initializes a Firebase app instance.

 

firebase.js

import firebase from "firebase/app";
import "firebase/database";
import dotenv from "dotenv";
dotenv.config();

var firebaseConfig = {
  apiKey: process.env.REACT_APP_APIKEY,
  authDomain: process.env.REACT_APP_AUTHDOMAIN,
  databaseURL: process.env.REACT_APP_DATABASEURL,
  projectId: process.env.REACT_APP_PROJECTID,
  storageBucket: process.env.REACT_APP_STORAGEBUCKET,
  messagingSenderId: process.env.REACT_APP_MSGSENDERID,
  appId: process.env.REACT_APP_APPID,
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);

let realTimeDB = firebase.database().ref(); //how to find real-time db location
export default realTimeDB;

firebase.database.Reference

: A Reference represents a specific location in your Database and can be used for reading or writing data to that Database location.

 

Comparison with the case of Cloud Firestore / Storage

import firebase from "firebase/app";
import "firebase/storage"; //store images
import "firebase/firestore"; //Cloud firestore
import "firebase/auth";
import dotenv from "dotenv";
dotenv.config();
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
var firebaseConfig = {
  apiKey: process.env.REACT_APP_APIKEY,
  authDomain: process.env.REACT_APP_AUTHDOMAIN,
  projectId: process.env.REACT_APP_PROJECTID,
  storageBucket: process.env.REACT_APP_STORAGEBUCKET,
  messagingSenderId: process.env.REACT_APP_MESSAGESENDER,
  appId: process.env.REACT_APP_APPID,
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);

const projectStorage = firebase.storage(); //This reference points to the root of Cloud Storage bucket.
const projectFirestore = firebase.firestore();
const timeStamp = firebase.firestore.FieldValue.serverTimestamp;
const projectAuth = firebase.auth();

export { projectStorage, projectFirestore, timeStamp, projectAuth };

Structure of Database

1) Realtime Database

Stores data as one large JSON tree.

  • Simple data is very easy to store.
  • Complex, hierarchical data is harder to organize at scale.

 

2) Cloud Firestore

Stores data as collections of documents.

  • Simple data is easy to store in documents, which are very similar to JSON.
  • Complex, hierarchical data is easier to organize at scale, using subcollections within documents.
  • Requires less denormalization and data flattening.

 

Common Sense

 

  • Both Realtime Database and Cloud Firestore are NoSQL Databases.
  • Client-first SDKs, with no servers to deploy and maintain
  • Realtime updates
  • Free tier, then pay for what you use

Other Differences

  Realtime DB

Cloud Firestore

Offline support iOS and Android clients

iOS, Android, and web clients

Presence(User) supported

Not supported natively

Querying Deep queries with limited sorting and filtering functionality

Indexed queries with compound sorting and filtering

Writes and transactions Basic write and transaction operations

Advanced write and transaction operations

Reliability and performance a regional solution

a regional and multi-region solution that scales automatically

Scalability Scaling requires *sharding

Scaling is automatic

Security Cascading rules language that separates authorization and validation

Non-cascading rules that combine authorization and validation

*Sharding: a database architecture pattern related to horizontal partitioning — the practice of separating one table’s rows into multiple different tables, known as partitions.

For more detail: nesoy.github.io/articles/2018-05/Database-Shard

 

source from: firebase.google.com/docs/firestore/rtdb-vs-firestore?hl=en


How to make CRUD function

C.R.U.D.

 

1. Create / Update

"addOrEdit" method

1) Get input info from ContactForm.js when submit button clicked

2-1) If Edit button is not clicked, push new info to database

2-2) If Edit button is clicked, set new info to the element accordingly by using currenId

 

2. Read

"useEffect" method

Snapshot database

 

3. Delete

"handleDelete" method

Delete selected data by using currenId

 

Contacts.js

function Contacts() {
  const [contactObjs, setContactObjs] = useState({})
  const [currentId, setCurrentId] = useState("")

  const addOrEdit = obj =>{
    if(currentId === ""){
      realTimeDB.child('contacts').push(
        obj,
        err => {
          if(err) {
            console.log(err)
          } else {
            setCurrentId('')
            }
        })
    } else {
      realTimeDB.child(`contacts/${currentId}`).set(
        obj,
        err => {
          if(err) {
            console.log(err)
            } else {
              setCurrentId('')
            }
        })
    }
  }
  const handleDelete = (currentId) => {
    if(window.confirm('Are you sure to delete this record?')){
      realTimeDB.child(`contacts/${currentId}`).remove(
        err => {
          if(err) {
            console.log(err)
          } else {
            setCurrentId('')
            }
        })
    }
  }

  useEffect(() => {
    realTimeDB.child('contacts').on('value', snapshot => {
      if(snapshot.val() != null) {
        setContactObjs({
          ...snapshot.val()
        })
      } else {
        setContactObjs({})
      }
    })
  },[])

  return (
    ...
    ContactForm {...({ addOrEdit, currentId, contactObjs})}/>
    ... 
      <tbody>
            {
              Object.keys(contactObjs).map(id=>{ 
                //객체 그룹일 때 Object.keys 를 이용하여 배열화 시킬 수 있는데,
                //map 의 각 요소는 id(데이터베이스에서 임의로 만든 id값) 이다.  
                return (                
                <tr key={id}>
                  <td>{contactObjs[id].fullName}</td>
                  <td>{contactObjs[id].mobile}</td>
                  <td>{contactObjs[id].email}</td>
                  <td>
                    <div className="btn text-primary" onClick={() => setCurrentId(id)}>
                      <i className="fas fa-pencil-alt"></i>
                    </div>
                    <div className="btn text-danger" onClick={() => handleDelete(id)}>
                      <i className="fas fa-trash-alt"></i>
                    </div>
                  </td>
                </tr>)
              })
            }
          </tbody>
  )
}

export default Contacts;

ContactForm.js

import React, {useState, useEffect} from "react";

function ContactForm( { addOrEdit, currentId, contactObjs} ) {
  const initialFieldValues = {
    fullName:"",
    mobile:"",
    email:"",
    address:""
  }

  const[values, setValues] = useState(initialFieldValues);
  const handleInputChange = e =>{
    const { name, value } = e.target;
    setValues({...values, [name]: value})
  }
  
  const handleFormSubmit = (e) => {
    e.preventDefault();
    addOrEdit(values);
  }
  //edit 을 클릭하면 id 값이 전달된다.
  useEffect(()=>{
    if(currentId === ""){
      setValues({...initialFieldValues})
    } else {
      setValues({...contactObjs[currentId]})
    }
  // eslint-disable-next-line react-hooks/exhaustive-deps
  },[currentId, contactObjs])

  return (
    <form action="" autoComplete="off" onSubmit={handleFormSubmit}>
      <div>
        <div className="form-group input-group">
          ...
          <input className="form-control" placeholder="Full Name" name="fullName" value={values.fullName} onChange={handleInputChange}/>
        </div>
        <div className="form-group input-group">
          ...
          <input className="form-control" placeholder="Mobile Number" name="mobile" value={values.mobile} onChange={handleInputChange}/>
        </div>
        <div className="form-group input-group">
          ...
          <input className="form-control" placeholder="E-mail" name="email" value={values.email} onChange={handleInputChange}/>
        </div>
        <div className="form-group input-group">
          ...
          <input className="form-control" placeholder="Address" name="address" value={values.address} onChange={handleInputChange}/>
        </div>
      </div>
      <div className="form-group submit">
        <input type="submit" value={currentId === "" ? "Save":"Update"} className="btn btn-primary btn-block"/>
      </div>
    </form>
    )
}

export default ContactForm;

Efficient State management

Utilize name / value props to update values(fullName, mobile, email, address) easily.

import React, {useState, useEffect} from "react";

function ContactForm( { addOrEdit, currentId, contactObjs} ) {
  const initialFieldValues = {
    fullName:"",
    mobile:"",
    email:"",
    address:""
  }

  const[values, setValues] = useState(initialFieldValues);
  //here is the point!
  const handleInputChange = e =>{
    const { name, value } = e.target;
    setValues({...values, [name]: value})
  }
  
...

  return (
    <form action="" autoComplete="off" onSubmit={handleFormSubmit}>
      <div>
        <div className="form-group input-group">
          ...
          <input className="form-control" placeholder="Full Name" name="fullName" value={values.fullName} onChange={handleInputChange}/>
        </div>
        ...
    </form>
    )
}

export default ContactForm;

How to make table

Concept

<table>
    <thead> : defines a set of rows defining the head of the columns of the table.
        <tr> : Table Row Element (<tr>) defines a row of cells in a table
            <th>menu</th> : defines a cell as header of a group of table cells
            <th>price</th>
        </tr>
    </thead>
    <tbody> :  encapsulates a set of table rows that comprises the body of the table 
        <tr>
            <td>steak</td>
            <td>45000</td>
        </tr>
        <tr>
            <td>wine</td>
            <td>45000</td>
        </tr>
    </tbody>
    <tfoot> : Its value will be null if there is no such element.
        <tr>
            <td>Total</td>
            <td>103000</td>
        </tr>
    </tfoot>
</table>

 

 <table className="table table-borderless table-stripped">
          <thead className="thead-light">
            <tr>
              <th>Full Name</th>
              <th>Mobile</th>
              <th>Email</th>
              <th>Action</th>
            </tr>
          </thead>
          <tbody>
            {
              Object.keys(contactObjs).map(id=>{ 
                return (                
                <tr key={id}>
                  <td>{contactObjs[id].fullName}</td>
                  <td>{contactObjs[id].mobile}</td>
                  <td>{contactObjs[id].email}</td>
                  <td>
                    <div className="btn text-primary" onClick={() => setCurrentId(id)}>
                      <i className="fas fa-pencil-alt"></i>
                    </div>
                    <div className="btn text-danger" onClick={() => handleDelete(id)}>
                      <i className="fas fa-trash-alt"></i>
                    </div>
                  </td>
                </tr>)
              })
            }
          </tbody>
</table>

 

 

 

Learn from:

youtu.be/pI4438IHBYY

Comments