21.10.25 ๊ณต๋ถ๊ธฐ๋ก๐งโ๐ป
FireBase, React๋ฅผ ํ์ฉํ ํธ์ํฐ ํด๋ก ์ฝ๋ฉ๐งโ๐ป
์ค๋ ์๋ฃํ ๋ชฉ๋ก
1. ํธ์ ์ญ์ ๊ธฐ๋ฅ
2. ํธ์ ์์ ๊ธฐ๋ฅ
3. ํธ์ ์ด๋ฏธ์ง ์ฒจ๋ถ ๋ฐ ์ญ์ ๊ธฐ๋ฅ
(์๊ณ ๋ฆฌ์ฆ ์์ฃผ ์กฐ๊ธ..)
1. ํธ์ ์ญ์ ๊ธฐ๋ฅ
Nweet.js
const NweetTextRef = doc(dbService,"nweets", `${nweetObj.id}`);
// ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ํธ์์ ์์ด๋๋ฅผ ์ฐพ๊ธฐ ์ํ ์ฝ๋.
const onDeleteClick = async () => { // ํธ์ ์ญ์ ํจ์
const ok = window.confirm("Are you sure you want to delete this tweet?");
if(ok){
await deleteDoc(NweetTextRef); // ํธ์ ์ญ์ ๊ธฐ๋ฅ
};
}
.
.
.
<button onClick={onDeleteClick}>Delete tweet</button>
๋ด๊ฐ ์ด ํธ์์ ์ญ์ ํ๊ฑฐ๋ ์์ ํ๊ธฐ ์ํด์๋ ๋จผ์ ํ์ด์ด๋ฒ ์ด์ค์ ๋ด๊ฐ ์ด ํธ์์ ์์ด๋๋ฅผ ์ฐพ์์ผํ๋ค.
๋ฌธ์ ์์ด๋๋ nweetObj.id์ ์๊ธฐ ๋๋ฌธ์ doc(dbService,"nweets", ${nweetObj.id}
)๋ฅผ ์ด์ฉํ์ฌ ํธ์์ ์์ด๋๋ฅผ ๋ฐ์์ ๋ณ์์ ์ ์ฅํ๋ค.
๋ณ์์ ๋ฃ์ ์ด์ ๋ ํธ์์์ด๋๋ฅผ ๋ฐ์์ค๋ ์ฝ๋๊ฐ ๋๋ฌด ๊ธธ๊ณ ๋ณต์กํ๊ธฐ ๋๋ฌธ์ ๋ณด๊ธฐ ์ฝ๊ฒ ํ๊ธฐ ์ํด์ ๋ณ์๋ฅผ ์ด์ฉํ๋ค.
ํธ์์ ์ญ์ (๋ฌธ์๋ฅผ ์ญ์ )ํ๋ ํจ์๋ deleteDoc()ํจ์๋ฅผ ์ด์ฉํ๋๋ฐ ์ด ํจ์๋ ํ์ด์ด๋ฒ ์ด์ค์์ ์ฌ์ฉํ๋ ํจ์๋ค. ๋ฒํผ์ Onclick ์์ฑ์ ์ค์ ๋ฒํผ์ ํด๋ฆญํ๋ฉด onDeleteClick ํจ์๊ฐ ๋ฐ๋ํ ์ ์๊ฒ ๋ง๋ค์๋ค.
๊ทธ๋ฆฌ๊ณ ๋ฒํผ์ ๋๋ ์ ๋ ์ ๋ง ์ญ์ ํ์๊ฒ ์ต๋๊น?์ ๊ฐ์ ์ฐฝ์ ๋์ด ํ์ธ์ ๋๋ฅด๋ฉด ์ญ์ ๊ฐ ๋ ์ ์๊ฒ ์ฝ๋๋ฅผ ์งฐ๋ค.
์ฐธ๊ณ : https://firebase.google.com/docs/firestore/manage-data/delete-data?hl=ko
2. ํธ์ ์์ ๊ธฐ๋ฅ
nweet.js
const [editing, setEditing] = useState(false);
// ์ด ์ฝ๋๋ ์์ ๋ฒํผ์ ํด๋ฆญํ์ ๋ ์
๋ ฅ๋๊ณผ ๋ฒํผ์ด ๋จ๊ฒํ๋ ๊ธฐ์ค์ ์.
const [newNweet, setNewNweet] = useState(nweetObj.nweet)
// ์์ ํ ๋ ์
๋ ฅ๋์ ๊ธฐ์กด์ ํธ์์ ๋ํ๋ด๊ธฐ ์ํ state
// .
// .
const toggleEditing = () => {setEditing((prev) => !prev)}
const onSubmit = async (event) => {
event.preventDefault();
await updateDoc(NweetTextRef,{
nweet: newNweet,
});
setEditing(false);
}
const onChange = (event) => {
const {
target : {value},
} = event;
setNewNweet(value);
}
.
.
{editing ? (
<>
<form onSubmit={onSubmit}>
<input onChange={onChange} type="text" placeholder ="Edit you tweet!" value={newNweet} required />
<input type ="submit" value="Update tweet"/>
</form>
<button onClick={toggleEditing}>Cancel</button>
</>
) :
.
.
<button onClick={toggleEditing}>Edit Nweet</button>
ํธ์ ์์ ๊ธฐ๋ฅ์ ์ญ์ ๋ณด๋ค ๋ ๋ณต์กํ๋ค. ์์ ๋ฒํผ์ ๋๋ฅด๋ฉด ๊ธ์ ์
๋ ฅํ ์ ์๊ฒ submit์ ์
๋ ฅํ๋ค.
์์ ๋ฒํผ์ ๋๋ฅด๋ฉด submit๊ณผ ์์ ๋ฒํผ, ์ทจ์๋ฒํผ์ด ๋์ฌ ์ ์๊ฒ ํ๊ณ ์ถ์๋ค.
๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ๊ธฐ์ค์ ์ ๋ง๋ค์ด์ผ ํ๋ค. ๊ทธ๋์ useState๋ฅผ ์ด์ฉํ์ฌ setEditing์ด๋ผ๋ ํจ์๋ฅผ ๋ง๋ค์ด
์
๋ ฅ๋๊ณผ ๋ฒํผ์ด ๋์ค๋ ๊ธฐ์ค์ ์ ๋ง๋ค์๋ค.
๊ทธ๋ฆฌ๊ณ ์์ ํ๊ธฐ ์ ์ ๊ธฐ์กด์ ํธ์ ๊ธ์ด ๋ํ๋๊ฒ ํ๊ธฐ ์ํด setNewNweet๋ ๋ง๋ค์๋ค.
๊ทธ๋ฆฌ๊ณ onChangeํจ์๋ฅผ ๋ง๋ค์๋๋ฐ ์ ๋ ฅ๋์ ํ์คํธ๋ฅผ ์ ๋ ฅํด์ผํ๋ ๊ฒฝ์ฐ onchangeํ๋กญ์ค, ํจ์ ์์ ์ ํด์ผํ๊ธฐ ๋๋ฌธ์ ๋ง๋ค์๋ค. ๋ง์ฝ onChange๊ฐ ์์ผ๋ฉด ์ ๋ ฅ๋์ ๊ธ์ ์ ๋ ฅํ ์ ์๊ฒ ๋๋ค.
onChange ํจ์ ์์ setNewNweet(value);๊ฐ ์จ์๋๋ฐ, ์ด๋ ํค๋ณด๋ ์ ๋ ฅํ ๋ ํจ์์ value์ธ์๋ก ์ ๋ ฅ๊ฐ์ด ๋์ด๊ฐ๊ณ value๊ฐ์ newNweet์ ๋ฐ์ํด์ ์ ๋ ฅ๋์ ์ ๋ ฅํ ํ ์คํธ๊ฐ ๋ณด์ด๊ฒ ํ๋ค.
const toggleEditing = () => {setEditing((prev) => !prev)}
์ด ์ฝ๋๋ ์ด์ ์ํ๋ฅผ setEditing์ ๋๊ฒจ์ค ์ฒซ๋ฒ์งธ ์ธ์๋ก ๋ฐ์ ๋ค์ !์ฐ์ฐ์๋ฅผ ์ด์ฉํ์ฌ ์ด์ ์ํ๋ฅผ ๊ด๋ฆฌ ํ๊ธฐ ์ํด ์ฌ์ฉํ๋ค.
{editing ? (
<>
<form onSubmit={onSubmit}>
<input onChange={onChange} type="text" placeholder ="Edit you tweet!" value={newNweet} required />
<input type ="submit" value="Update tweet"/>
</form>
<button onClick={toggleEditing}>Cancel</button>
</>
) :
์์ ๋ฒํผ์ ๋๋ฅด๋ฉด editing์ด false์์ true๋ก ๋ฐ๋๋ฉด์ ์ ๋ ฅ๋๊ณผ ๋ฒํผ์ด ๋์ฌ ์ ์๊ฒ ํ๋ค.
const onSubmit = async (event) => {
event.preventDefault();
await updateDoc(NweetTextRef,{
nweet: newNweet,
});
setEditing(false);
}
๋ onSubmit์ด ํต์ฌ์ด๋ผ๊ณ ์๊ฐํ๋ค, ๋จผ์ event.preventDefault();๋ submit์ ํ์ ๋ ์๋ก๊ณ ์นจ์ด ๋์ง ์๊ฒ ๋ฃ์๊ณ updateDoc๋ผ๋ ํจ์๋ฅผ ์ด์ฉํ์ฌ ์์ ์ ํ๋ค.
ํ์ด์ด๋ฒ ์ด์ค์ ๋์์๋ ์ฌ์ฉ๋ฒ์ด๋ค.
NweetTextRef๋ ์๊น ์์์ ์ค๋ช
ํ ๊ฒ ์ฒ๋ผ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ํธ์ ์์ด๋๋ฅผ ์ฐพ๊ธฐ ์ํ ๋ณ์๋ค.
nweet : newNweet๋ฅผ ์
๋ ฅํ ๊ฒ์ ์
๋ ฅ๋์ ์๋ก์ด ํธ์์ ์
๋ ฅํ๊ธฐ ์ํด ์ํ๊ด๋ฆฌ๋ฅผ ์ํ newNweet ์
๋ฐ์ดํธ๋ฅผ ์์ผ์ค ์์ ์ ํ ์ ์๊ฒ ํ๋ค.
๊ทธ๋ฆฌ๊ณ submit์ด ์๋ฃ๊ฐ ๋๋ฉด ์
๋ ฅ๋๊ณผ ์์ ๋ฒํผ์ด ์ฌ๋ผ์ง๊ฒ setEditing์ false๋ก ๋ง๋ค์ด์คฌ๋ค.
3. ํธ์ ์ด๋ฏธ์ง ์ฒจ๋ถ ๋ฐ ์ญ์ ๊ธฐ๋ฅ
ํธ์ ์ด๋ฏธ์ง ์ฒจ๋ถ
home.js
const [attachment, setAttachment] = useState("");
const onFileChange = (event) =>{
const {target : {files},
} = event;
const theFile = files[0];
const reader = new FileReader();
reader.onloadend = (finishedEvent) => {
const {
currentTarget : {result},
} = finishedEvent;
setAttachment(result);
};
reader.readAsDataURL(theFile);
};
.
.
.
<input type="file" accept="image/*" onChange={onFileChange}/>
์ด๋ฏธ์ง๋ฅผ ์ฒจ๋ถํ๊ฒ ํ๊ธฐ ์ํด input ํ์
์ ํ์ผ๋ก ๋ฐ์ ์ด๋ฏธ์ง๋ฅผ ๋ฐ์์ฌ ์ ์๊ฒ ์ฝ๋๋ฅผ ๋จผ์ ์งฐ๋ค.
์ด๋ฏธ์ง๋ฅผ ๋ํ๋ด๊ธฐ ์ํด์๋ ์ด๋ฏธ์ง ํ์ผ์ ์ ํํ target์ ์์์ผํ๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์
console.log๋ก files๋ฐฐ์ด์ด ํ๊ฒ์ด๋ผ๋ ๊ฒ์ ์์๋ค.
files ๋ฐฐ์ด์ theFile ๋ณ์์ ์ ์ฅํด๋จ๋ค.
ํ์ง๋ง ํ์ผ์ ์น๋ธ๋ผ์ฐ์ ์ ์ถ๋ ฅํ๋ ค๋ฉด ๋ธ๋ผ์ฐ์ API๋ฅผ ์ฌ์ฉํด์ผํ๋ค๋ ๊ฒ์ ์์๋ค.
๊ทธ๋์ FileReader ํจ์๋ฅผ ์ด์ฉํ๋ค.
(์ฌ์ฉ๋ฒ https://developer.mozilla.org/ko/docs/Web/API/FileReader)
๊ทธ ํ reader ๋ณ์์ ๋ฃ์ด์ค ํ readAsDataURL()ํจ์๋ฅผ ์ด์ฉํ์ฌ ํ์ผ ์ ๋ณด๋ฅผ ์ธ์๋ก ๋ฐ์ ํ์ผ ์์น๋ฅผ url๋ก ๋ฐํํด์คฌ๋ค.
์ด ํจ์๋ ๋จ์ํ๊ฒ ์ฌ์ฉํ ์๋ ์๊ณ ์น๋ธ๋ผ์ฐ์ ๊ฐ ํ์ผ์ ์ธ์ํ๊ณ ์ธ์์ด ๋๋๋ ์์ ์ ํฌํจํ๊ณ ์์ด ๊ทธ ์์ ์ ํจ๊ป ๊ด๋ฆฌํด์ค์ผ url์ ์ป์ ์ ์๋ค.
(FileReader.readAsDataURL()
์ง์ ๋ ์ ๋ด์ฉ ์ฝ๊ธฐ๋ฅผ ์์ํฉ๋๋ค. Blob์๋ฃ๋๋ฉด result์์ฑ data:์ ํ์ผ ๋ฐ์ดํฐ๋ฅผ ๋ํ๋ด๋ URL์ด ํฌํจ ๋ฉ๋๋ค.)
๊ทธ๋ฆฌ๊ณ onloadendํจ์๋ฅผ ์ด์ฉํ์ฌ ๊ฒฐ๊ณผ ๊ฐ์ด ๋์จ ์ดํ ์ธ์์ด ๋๋๋ ์์ ์ดํ์ ์ด๋ฒคํธ ๊ฐ์ ์ฌ์ฉํ ์ ์๊ฒ ํด์คฌ๋ค. ์ด ํจ์๋ฅผ ์ด์ฉํ์ฌ ํ์ผ์ url์ด ์๋ result๋ผ๋ ํ๊ฒ์ ์ฐพ์๋ค.
const [attachment, setAttachment] = useState("");
์ฌ์ง์ Url์ ๊ด๋ฆฌํ๊ธฐ ์ํ ์ํ๊ฐ ์์ด์ผ ํ๊ธฐ ๋๋ฌธ์ useState๋ฅผ ์ด์ฉํด setAttachment ํจ์๋ฅผ ๋ง๋ค์ด result(url)๋ฅผ ์ ์ฅํ๋ค.
{attachment && (
<div>
<img src={attachment} width="50px" height="50px" />
</div>
)}
๊ทธ๋์ ์ด๋ฏธ์ง url์ด ์์ ๋๋ง ์ด๋ฏธ์ง๋ฅผ ์ฒจ๋ถํ ์ ์๊ฒ src์ attachment๋ฅผ ๋ฃ์ด์คฌ๋ค.
์ด๋ฏธ์ง ์ญ์ ๊ธฐ๋ฅ
import {useRef} from React;
const fileInput = useRef();
const onClearPhoto= () =>{
setAttachment("");
fileInput.current.value = "";
}
<input type="file" accept="image/*" onChange={onFileChange} ref={fileInput} />
<button onClick={onClearPhoto}>Clear</button>
์ด๋ฏธ์ง ์ญ์ ๋ฅผ ํ๊ธฐ ์ํด ์ญ์ ํจ์๋ฅผ ๋ง๋ค์ด์คฌ๋๋ฐ, ๊ฐ๋จํ๊ฒ ์ค๋ช
ํ์๋ฉด ์ด๋ฏธ์ง url๋ฅผ ์ ์ฅํ๋ setAttachmentํจ์์ Null๊ฐ์ ๋ฃ์ด url์ ์๊ฒ ํ๋ค.
ํ์ง๋ง ์ญ์ ์ดํ์ ์ด๋ฏธ์ง ํ์ผ๋ช
์ด ๋จ์์์ด ์ง์ฐ๊ธฐ ์ํด useRef()ํ
์ ์ด์ฉํ์ฌ fileInput๋ณ์๋ฅผ ๋ง๋ค๊ณ
clear์ ๋๋ ์ ๋ fileInput์์ ์๋ current.value์ ๊ฐ์ ๊ฐ์ ธ์์ ๋น์์ฃผ๊ฒ ํ๋ค.
(์ฌ์ฉ๋ฒ : https://ko.reactjs.org/docs/hooks-reference.html#useref)
์ ์ฒด ์ฝ๋
home.js
import { dbService } from 'fbase';
import React,{useState, useEffect, useRef} from "react";
import {addDoc, collection,query, onSnapshot,orderBy} from "firebase/firestore";
import Nweet from "components/Nweet"
const Home = ({userObj}) => {
const [nweet, setNweet] = useState("");
const [nweets, setNweets] = useState([]); // ํธ์๋ค์ ์ํ๋ก ๋ฐ์์ ๋ณด๊ดํด์ผํ๊ธฐ ๋๋ฌธ์ ๋ฐฐ์ด๋ก usestate ์์ฑ
const [attachment, setAttachment] = useState(""); // ์ฌ์งํ์ผ url์ ๊ด๋ฆฌํ๊ธฐ ์ํ state
useEffect(() => {
onSnapshot( // OnSnapshot ํจ์๋ฅผ ์ด์ฉํ์ฌ ๋ชจ๋ ์ค๋
์ท์ ๋ฐํํจ.
query(collection(dbService, "nweets"), orderBy("createdAt", "desc")),
(snapshot) => {
const nweetArray = snapshot.docs.map((doc) => ({
id: doc.id, // map ํจ์๋ฅผ ์ด์ฉํ์ฌ ์ค๋
์ท์์ ์ํ๋ ๋ฐ์ดํฐ๋ง ๋ฝ์์ ๋ฐฐ์ดํ ์ํจ ํ ํ๋ฉด์ ๋ํ๋.
...doc.data(), // ์ ์ ์ฌ์ฉํ๋ Foreachํจ์๋ ๋งค ์ํ๋ง๋ค setNweets๋ฅผ ์ฌ์ฉํด์ผํ์ง๋ง, mapํจ์๋ ์ํํ๋ฉด์ ๋ง๋ ๋ฐฐ์ด์ ๋ฐํํ๋ฏ๋ก
// ๋ฐํํ ๋ฐฐ์ด์ 1๋ฒ๋ง setNweetํจ์์ ์ ๋ฌํ๋ฉด ๋๊ธฐ ๋๋ฌธ์ ํจ์ฌ ํจ์จ์ ์ด๋ค.
}));
setNweets(nweetArray);
}
);
}, []);
const onSubmit = async (e) => {
try{
e.preventDefault();
const docRef = await addDoc(collection(dbService, "nweets"),
{
nweet,
createdAt: Date.now(),
creatorId : userObj.uid, // db์ ์ ์ ์์ด๋ ์ถ๊ฐ
}); // ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์ฑ
console.log("Document Written with Id:", docRef.id);
}catch(error){
console.log("Error adding document", error)
}
setNweet("");
};
const onChange = (event) =>{
const {target : {value},
}= event;
setNweet(value);
};
const onFileChange = (event) =>{
const {target : {files},
} = event;
const theFile = files[0];
const reader = new FileReader();
reader.onloadend = (finishedEvent) => {
const {
currentTarget : {result},
} = finishedEvent;ใ
setAttachment(result);
};
reader.readAsDataURL(theFile); // ํ์ผ ์ ๋ณด๋ฅผ ์ธ์๋ก ๋ฐ์ ํ์ผ ์์น๋ฅผ url๋ก ๋ฐํํด์ค.
}; // ์ฌ์ง ํ์ผ ์
๋ก๋ ์ฝ๋
const fileInput = useRef(); // ์ด๋ฏธ์ง ํ์ผ๋ช
์ ์ง์ฐ๊ธฐ ์ํด useRef ํ
์ฌ์ฉ
const onClearPhoto= () =>{
setAttachment("");
fileInput.current.value = "";
}
return (
<>
<div>
<form onSubmit={onSubmit}>
<input value={nweet} onChange={onChange} type = "text" placeholder ="what's on your mind" maxLength={120} />
<input type="file" accept="image/*" onChange={onFileChange} ref={fileInput} />
<input type="submit" value="nweet"/>
{attachment && (
<div>
<img src={attachment} width="50px" height="50px" />
<button onClick={onClearPhoto}>Clear</button>
</div>
)}
</form>
<div>
{nweets.map((nweet) => (
// map ํจ์๋ฅผ ์ด์ฉํ์ฌ nweets ๋ฐฐ์ด์ ์ํํ๋ฉด์ jsx๋ฅผ ๋ฐํํ๊ฒ ๋ง๋ค์ด์ ํธ์ ๋ฐฐ์ด๋ค์ ์น์ ๋ํ๋.
<Nweet
key={nweet.id}
nweetObj={nweet}
isOwner={nweet.creatorId === userObj.uid}
// isOwner nweet.creatorId === userObj.uid๊ฐ ๊ฐ์์ผ ๊ถํ์ ์ค ์ ์๊ฒ ์ค์ .
/>
))}
</div>
</div>
</>
);
};
export default Home;
nweet.js
import React ,{useState}from "react";
import { dbService } from 'fbase';
import {doc,deleteDoc,updateDoc} from "firebase/firestore";
const Nweet = ({nweetObj, isOwner}) =>{
const [editing, setEditing] = useState(false);
// ์ด ์ฝ๋๋ ์์ ๋ฒํผ์ ํด๋ฆญํ์ ๋ ์
๋ ฅ๋๊ณผ ๋ฒํผ์ด ๋จ๊ฒํ๋ ๊ธฐ์ค์ ์.
const [newNweet, setNewNweet] = useState(nweetObj.nweet)
// ์์ ํ ๋ ์
๋ ฅ๋์ ๊ธฐ์กด์ ํธ์์ ๋ํ๋ด๊ธฐ ์ํ state
const NweetTextRef = doc(dbService,"nweets", `${nweetObj.id}`);
// ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ํธ์์ ์์ด๋๋ฅผ ์ฐพ๊ธฐ ์ํ ์ฝ๋.
const onDeleteClick = async () => { // ํธ์ ์ญ์ ํจ์
const ok = window.confirm("Are you sure you want to delete this tweet?");
if(ok){
await deleteDoc(NweetTextRef); // ํธ์ ์ญ์ ๊ธฐ๋ฅ
};
}
const toggleEditing = () => {setEditing((prev) => !prev)}
const onSubmit = async (event) => {
event.preventDefault();
await updateDoc(NweetTextRef,{
nweet: newNweet,
});
setEditing(false);
console.log(nweetObj.id, newNweet);
}
const onChange = (event) => {
const {
target : {value},
} = event;
setNewNweet(value);
} // ์
๋ ฅ๋์ ํ์คํธ๋ฅผ ์
๋ ฅํด์ผํ๋ ๊ฒฝ์ฐ onchangeํ๋กญ์ค, ํจ์ ์์
์ ํด์ผํ๋ค.
return (
<div>
{editing ? (
<>
<form onSubmit={onSubmit}>
<input onChange={onChange} type="text" placeholder ="Edit you tweet!" value={newNweet} required />
<input type ="submit" value="Update tweet"/>
</form>
<button onClick={toggleEditing}>Cancel</button>
</>
) : (
<>
<h4>{nweetObj.nweet}</h4>
{isOwner && (
<>
<button onClick={onDeleteClick}>Delete tweet</button>
<button onClick={toggleEditing}>Edit Nweet</button>
</>
)}
</>
)}
</div>
);
};
export default Nweet;
์ค๋ ๊ฒฐ๋ก
๊ณต๋ถํ ์๋ก useState์ ์ค์ํจ์ ๋๋๋ค.. ์ฒ์ ์ฌ์ฉํ ๋๋ ๋ฌด์จ ๋ง์ธ์ง ๋์ ํ ์ดํด๊ฐ ์ ๊ฐ๋๋ฐ
์ฌ์ฉํด๋ณผ ์๋ก ์ด๋์ ๋ ๊ฐ์ด ์จ๋ค, ๋นจ๋ฆฌ ํธ์ํฐ ํด๋ก ์ฝ๋ฉ์ ๋๋ด๊ณ es6๋ ๋ฆฌ์กํธ๋ฅผ ๋ ๊ณต๋ถํ๊ณ ์ถ๋ค..
์์ ๊ธฐ๋ฅ์์ ์๋ฌ๊ฐ ๋ง์์ ๋๋ฌด ๋ง์ ์๊ฐ์ ์๋ชจํ๋ค..๐ฅฒ
์ง์ค๋ ฅ์ ๋์ด๊ธฐ ์ํด ๋ด์ผ์ ์นดํ์์ ๊ณต๋ถํ๋ ค๊ณ ํ๋ค!
Author And Source
์ด ๋ฌธ์ ์ ๊ดํ์ฌ(21.10.25 ๊ณต๋ถ๊ธฐ๋ก๐งโ๐ป), ์ฐ๋ฆฌ๋ ์ด๊ณณ์์ ๋ ๋ง์ ์๋ฃ๋ฅผ ๋ฐ๊ฒฌํ๊ณ ๋งํฌ๋ฅผ ํด๋ฆญํ์ฌ ๋ณด์๋ค https://velog.io/@dduck/21.10.25-๊ณต๋ถ๊ธฐ๋ก์ ์ ๊ท์: ์์์ ์ ๋ณด๊ฐ ์์์ URL์ ํฌํจ๋์ด ์์ผ๋ฉฐ ์ ์๊ถ์ ์์์ ์์ ์ ๋๋ค.
์ฐ์ํ ๊ฐ๋ฐ์ ์ฝํ ์ธ ๋ฐ๊ฒฌ์ ์ ๋ (Collection and Share based on the CC Protocol.)
์ข์ ์นํ์ด์ง ์ฆ๊ฒจ์ฐพ๊ธฐ
๊ฐ๋ฐ์ ์ฐ์ ์ฌ์ดํธ ์์ง
๊ฐ๋ฐ์๊ฐ ์์์ผ ํ ํ์ ์ฌ์ดํธ 100์ ์ถ์ฒ ์ฐ๋ฆฌ๋ ๋น์ ์ ์ํด 100๊ฐ์ ์์ฃผ ์ฌ์ฉํ๋ ๊ฐ๋ฐ์ ํ์ต ์ฌ์ดํธ๋ฅผ ์ ๋ฆฌํ์ต๋๋ค