728x90
TransactionForm.jsx์์ฑ

import React from "react";
const TransactionForm = () => {
const [name, setName] = useState("");
const [amount, setAmount] = useState("");
const handleSubmit = (e) => {
e.preventDefault();
console.log({
name,
amount,
});
};
return (
<div>
<h3>๊ฑฐ๋ ์ถ๊ฐ</h3>
<form onSubmit={handleSubmit}>
<label>
<span>๊ฑฐ๋๋ช
:</span>
<input
type="text"
required
onChange={(e) => setName(e.target.value)}
value={name}
/>
</label>
<label>
<span>๊ฐ๊ฒฉ(์):</span>
<input
type="number"
required
onChange={(e) => setAmount(e.target.value)}
value={amount}
/>
</label>
<button>์ถ๊ฐ</button>
</form>
</div>
);
};
export default TransactionForm;
Home.jsx์ ์๋ก ์ถ๊ฐํ TransactionForm ์ปดํฌ๋ํธ ์ถ๊ฐ
import TransactionForm from "../../Components/TransactionForm";
import styles from "./Home.module.css";
const Home = () => {
return (
<div className={styles.container}>
<div className={styles.content}>๊ฑฐ๋ ๋ด์ญ</div>
<div className={styles.sidebar}>
<TransactionForm />
</div>
</div>
);
};
export default Home;
Home.module.css
.container {
display: grid;
grid-template-columns: 2fr 1fr;
max-width: 960px;
margin: 60px auto;
}
.content {
padding-right: 30px;
}
.sidebar {
padding-left: 30px;
}
.sidebar form {
padding: 20px;
background: #1f9751;
border-radius: 10px;
}
.sidebar input,
.sidebar select {
display: block;
width: 100%;
padding: 10px;
margin-top: 8px;
box-sizing: border-box;
border: 0;
border-radius: 4px;
color: #555;
font-size: 1em;
}
.sidebar label {
margin: 0 auto 20px;
display: block;
color: #fff;
}
.sidebar button {
color: #fff;
border: 2px solid #fff;
padding: 6px 12px;
background-color: transparent;
font-size: 1em;
border-radius: 4px;
cursor: pointer;
display: block;
width: 100%;
}
.sidebar h3 {
color: #1f9751;
margin-bottom: 20px;
}
.sidebar aside {
margin-top: 40px;
color: #555;
}
.sidebar aside li {
margin: 10px;
}



์ด์ ๊ฑฐ๋๋ด์ญ์ ๊ฐ์ ธ์ฌ๊ฑฐ์





hooks์ useFireStore.js์ถ๊ฐ

import { useEffect, useReducer, useState } from "react";
import { firedb, timestamp } from "../firebase/config";
//์ด๊ธฐ์ํ
let initalState = {
document: null,
isPending: false,
error: null,
success: false,
};
const firestoreReducer = (state, action) => {
switch (action.type) {
case "IS_PENDING":
return { isPending: true, document: null, success: false, errror: null };
case "ADDED_DOCUMENT":
return {
isPending: false,
document: action.payload,
success: true,
errror: null,
};
case "ERROR":
return {
isPending: false,
document: null,
success: false,
errror: action.payload,
};
default:
return state;
}
};
export const useFirestore = (collection) => {
const [response, dispatch] = useReducer(firestoreReducer, initalState);
const [isCancelled, setIsCancelled] = useState(false);
// DB ์ปฌ๋ ์
๋ ํผ๋ฐ์ค
const ref = firedb.collection(collection);
// ์ทจ์๊ฐ ์๋๊ฒฝ์ฐ์๋ง ๋์คํจ์นํ๊ธฐ
const dispatchIfNotCancelled = (action) => {
if (!isCancelled) {
dispatch(action);
}
};
// doc ์ถ๊ฐ
const addDocument = async (doc) => {
dispatch({ type: "IS_PENDING" });
try {
const createdAt = timestamp.fromDate(new Date());
const addedDocument = await ref.add({ ...doc, createdAt });
dispatchIfNotCancelled({
type: "ADDED_DOCUMENT",
payload: addedDocument,
});
} catch (err) {
dispatchIfNotCancelled({ type: "ERROR", payload: err.message });
}
};
useEffect(() => {
setIsCancelled(false);
return () => setIsCancelled(true);
}, []);
return { addDocument, response };
};
config.js์ ์๊ฐ ์ถ๊ฐํจ (export์๋ ์ถ๊ฐ)
//ํ์ด์ด ์คํ ์ด DB์๋น์ค
//init service
const firedb = firebase.firestore();
//์ธ์ฆ์๋น์ค
const fireauth = firebase.auth();
//timestamp ์๊ฐ
const timestamp = firebase.firestore.Timestamp;
useFireStore.js
// doc ์ถ๊ฐ
const addDocument = async (doc) => {
dispatch({ type: "IS_PENDING" });
try {
const createdAt = timestamp.fromDate(new Date()); //ํ์ฌ๋ ์ง์๊ฐ์ผ๋ก ๋ ์ง๋ฐ์ดํฐ ๋ง๋ค๊ธฐ
const addedDocument = await ref.add({ ...doc, createdAt }); //๋ ์ง์๊ฐ๊ณผ ํจ๊ป ์ ์ฅํ๊ธฐ
dispatchIfNotCancelled({
type: "ADDED_DOCUMENT",
payload: addedDocument,
});
} catch (err) {
dispatchIfNotCancelled({ type: "ERROR", payload: err.message });
}
};
ADDED_DOCUMENT ๋ฅผ ์ฌ์ฉํ์ฌ ์ ๊ฑฐ๋๋ด์ญ์ ์ถ๊ฐํ๋ค.
TransactionForm.jsx
import React, { useState } from "react";
import { useFirestore } from "../hooks/useFireStore";
const TransactionForm = ({ uid }) => {
const [name, setName] = useState("");
const [amount, setAmount] = useState("");
const [addDocument, response] = useFirestore("transactions"); //ํ์ด์ด์คํ ์ด์ ์๋ก ๋ฌธ์์ถ๊ฐ ๊ฐ์ ธ์ค๊ธฐ
const handleSubmit = (e) => {
e.preventDefault();
addDocument({
uid,
name,
amount,
});
};
//db์ ์๋ฌธ์ ์ ์ฅํ ํผ ๋ด์ฉ ์์ ๊ธฐ
useEffect(() => {
if (response.success) {
setName("");
setAmount("");
}
}, [response.success]);
return (
<div>
<h3>๊ฑฐ๋ ์ถ๊ฐ</h3>
<form onSubmit={handleSubmit}>
<label>
<span>๊ฑฐ๋๋ช
:</span>
<input
type="text"
required
onChange={(e) => setName(e.target.value)}
value={name}
/>
</label>
<label>
<span>๊ฐ๊ฒฉ(์):</span>
<input
type="number"
required
onChange={(e) => setAmount(e.target.value)}
value={amount}
/>
</label>
<button>์ถ๊ฐ</button>
</form>
</div>
);
};
export default TransactionForm;
์ค์ด 2์ฒ์ ์ถ๊ฐํด๋ด


์ถ๊ฐ๋ ๋์ง๋ง ์ค์๊ฐ์ผ๋ก ํ์ธ์ ํ๊ณ ์ถ๋ค.
useCollection.js

import { useEffect, useState } from "react";
import { firedb } from "../firebase/config";
export const useCollection = (collection) => {
const [documents, setDocuments] = useState(null);
const [error, setError] = useState(null);
useEffect(() => {
let ref = firedb.collection(collection);
const unsub = ref.onSnapshot(
(snapshot) => {
let results = [];
snapshot.docs.forEach((doc) => {
results.push({ ...doc.data(), id: doc.id }); //๋ชจ๋ ํ๋๊ฐ ์ถ๊ฐ๋๊ณ , doc id๋ ์ถ๊ฐ
});
setDocuments(results);
setError(null);
},
(err) => {
console.log(err);
setError("๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค.");
}
);
return () => unsub();
}, [collection]);
return { documents, error };
};
Home.jsx
๋ก๊ทธ์ธ ๋ ์ ์ ์ ๊ฑฐ๋๋ด์ญ๋ง ๋ณผ ์ ์๋๋ก
์กฐ๊ฑด ์ถ๊ฐ
import TransactionForm from "../../Components/TransactionForm";
import { useAuthContext } from "../../hooks/useAuthContext";
import { useCollection } from "../../hooks/useCollection";
import styles from "./Home.module.css";
import TransactionList from "./TransactionList";
const Home = () => {
const { user } = useAuthContext();
const { documents, error } = useCollection("transactions", [
"uid",
"==",
user.uid,
]);
return (
<div className={styles.container}>
<div className={styles.content}>
{error && <p>{error}</p>}
{documents && <TransactionList transactions={documents} />}
</div>
<div className={styles.sidebar}>
<TransactionForm uid={user.uid} />
</div>
</div>
);
};
export default Home;
TransactionList.jsx
import styles from "./Home.module.css";
const TransactionList = ({ transactions }) => {
return (
<div className={styles.transactions}>
{transactions.map((transaction) => (
<li key={transaction.id}>
<p className={styles.name}>{transaction.name}</p>
<p className={styles.amount}>{transaction.amount}์</p>
</li>
))}
</div>
);
};
export default TransactionList;
Home.module.css
/* ํธ๋์ ์
๋ฆฌ์คํธ ์คํ์ผ */
.transactions li {
margin: 30px auto;
border: 1px solid #f2f2f2;
box-shadow: 3px 3px 5px rgba(50, 50, 50, 0.1);
padding: 20px;
display: flex;
align-items: center;
position: relative;
overflow: hidden;
border-left: 4px solid #1f9751;
}
.transactions .name {
color: #777;
font-size: 1.4em;
}
.transactions .amount {
margin-left: auto;
margin-right: 40px;
color: #777;
font-weight: bold;
font-size: 1.6em;
}
.transactions button {
position: absolute;
top: 0;
right: 0;
background: #ddd;
color: #777;
border: none;
padding: 12px 8px;
text-align: center;
line-height: 0;
font-size: 0.9em;
cursor: pointer;
}
hong์ hong์ ๊ฑฐ๋๋ด์ญ๋ง ๋ณผ ์ ์๊ณ
๋ค๋ฅธ ์ ์ ๋ก ๋ก๊ทธ์ธํด์ ํ์ธํด๋ ๋ณธ์ธ์ ๊ฑฐ๋๋ด์ญ๋ง ํ์ธ๊ฐ๋ฅํ๋ค.

'FRONTEND > React' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| [๋ง์ด๋จธ๋์ฑ] ๋ณด์ (0) | 2023.12.05 |
|---|---|
| [๋ง์ด๋จธ๋์ฑ] ์ญ์ ํ๊ธฐ (1) | 2023.12.05 |
| [๋ง์ด๋จธ๋์ฑ] ๋ค๋น๊ฒ์ด์ ๊ฐ๋ (0) | 2023.12.04 |
| [๋ง์ด๋จธ๋์ฑ] ํด๋ฆฐ์ ํจ์ ์ถ๊ฐํ๊ธฐ/ ๋ก๊ทธ์ธ ๋ฐ ๋ก๊ทธ์ธ ์ ์ ์ ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ (2) | 2023.12.04 |
| [๋ง์ด๋จธ๋์ฑ] ํ์ด์ด๋ฒ ์ด์ค(DB) ์ฌ์ฉ/ํ์๊ฐ์ /๋ก๊ทธ์์ (1) | 2023.12.04 |