์ฃผ์ ์์
- ํด๋ผ์ด์ธํธ
- ์คํ์ผ ์์
- css ๋ฒ๋ค๋ง๊ณผ ํด๋์ค ์ ํ์๋ฅผ ํตํ ์คํ์ผ ์ ํ๊ธฐ
- spinner ์ค์ ๊ณผ state์ ๋ฐ๋ฅธ spinner ๋ ๋๋ง ํ ์คํธ
- ์๋ฒ
- updateTodo์์ ๊ฐ์ฒด๋ฅผ ๋๊ฒจ์ฃผ๋ ๋ฐฉ์์ผ๋ก ๋ฆฌํฉํ ๋ง
- ๋ผ์ด๋ธ๋ฌ๋ฆฌ
- useEffect์์ ์ด์ ์ ๊ฐ๊ณผ ํ์ฌ ๊ฐ์ ๋น๊ตํ๊ธฐ ์ํด ๋ฃ์ ์ ์๋๋ก ์ค๊ณ
- Object.keys()๋์ map ์๋ฃ๊ตฌ์กฐ๋ฅผ ์ฌ์ฉํ์ฌ ์ด๋ฒคํธ ํธ๋ค๋ฌ ๊ฒ์ ์ฑ๋ฅ ์ต์ ํ
ํ์ต ํค์๋
- firebase functions & firestore
- NOSQL
- ์๋ฒ๋ฆฌ์ค ์ํคํ ์ฒ
- useEffect
- useRef
- useContext
๊ณ ๋ฏผ ๋ฐ ํด๊ฒฐ๊ณผ์
state์ ํจ์๋ฅผ ๋์์ ๋ค๋ฅธ ์ปดํฌ๋ํธ์ ์ธ์๋ก ๋๊ฒจ์ค ๋
export default function Mainpage() {
...
const [isLoading, setIsLoading] = mhReact.useState(false);
async function fetchData() {
const data = await apicall.get("/todo");
setTodoList(data);
}
mhReact.useEffect(async () => {
await fetchData();
}, []);
...
return (
<div>
...
<TodoList
todoList={todoList}
fetchData={fetchData}
/>
<Spinner isLoading={isLoading} />
</div>
);
}
state์ ๋ฐ๋ฅธ ํ๋ฉด ๋ ๋๋ง์ ํ
์คํธํด๋ณด๊ณ ์๋ ์์ค์ TodoList์์ ๊ฐ ์์์ ๋ํด
์ด์ ๊ฐ์ด X ๋ฒํผ์ ๋ง๋ค์ด ๋๋ฅด๋ฉด ์ญ์ api ์์ฒญ์ด ๊ฐ ์ ์๋๋ก ๋ง๋ค์๋ค.
ํ์ง๋ง ์ญ์ api ์์ฒญ์ด ๊ฐ๊ณ ๋ ๋ค์๋ ๋ค์๊ธ ๋ฐ์ดํฐ๋ฅผ fetchํด์ ์ญ์ ํด์จ ๋ค ์ต์ ์ ๋ณด๋ฅผ ๊ฐฑ์ ํ๊ธฐ ์ํด์ ์์์ ์คํํ๋ fetchData๋ฅผ ๊ฐ์ ธ์ฌ ํ์๊ฐ ์์๋ค. ์์ ์ปดํฌ๋ํธ์์ setTodoList๋ฅผ ํตํด ํด๋น ๋ฆฌ์คํธ๋ค์ ๋ํด์ ๊ด๋ฆฌํ๊ณ ์๊ธฐ ๋๋ฌธ์ด๋ค.
import * as mhReact from "mhreact";
import { deleteTodo } from "../../features/todo";
import "./index.css";
export default function TodoList({ todoList, fetchData }) {
if (!todoList.length) {
return <h1>๋ก๋ฉ์ค...</h1>;
}
async function onClickDelete(id) {
try {
await deleteTodo(id);
await fetchData();
} catch (error) {
alert("์ญ์ ์ค ์ค๋ฅ๊ฐ ๋ฐ์ํ์ด์!");
}
}
return (
<ul class="todo-list">
{todoList.map((todo) => (
<div class="todo-item">
<li>{todo.detail}</li>
<button
class="todo-deleteButton"
onClick={() => onClickDelete(todo.id)}
>
โ
</button>
</div>
))}
</ul>
);
}
๋ฐ๋ผ์ ์ด๋ฐ ์์ผ๋ก fetchData ํจ์ ์์ฒด๋ฅผ ๊ฐ์ ธ์ delete ๋ฒํผ์ ๋๋ฅด๋ฉด delete api๋ฅผ ๋ณด๋ธ ํ์ fetchData๋ฅผ ํตํด์ ๋ค์๊ธ ์ ๋ณด๋ฅผ ๊ฐฑ์ ํ ์ ์๋๋ก ํด์ฃผ์๋ค.
export function destructuringFunctionalComponentWithRef(element) {
const duplicated = {};
Object.entries(element.props.refs).forEach(([ref, val]) => {
if (typeof val === "function") duplicated[ref] = val();
else duplicated[ref] = val;
});
return element.type(duplicated);
}ํ์ง๋ง ๋ด๊ฐ ์ค๊ณํ fiber๋ฅผ ๊ตฌ์ฑํ๋ ๊ณผ์ ์์ destructuringFunctionalComponentWithRef()๋ ํน์๋ ์ปดํฌ๋ํธ๊ฐ ์ํ๋ ๊ฒ๋ค ์ค ์ํ๋ฅผ ๋๊ฒจ์ฃผ๊ฒ ๋๋ค๋ฉด, ํค์๋ ๋ฃจํธ์ ๋ถ์ด์๋ ์ํ ์ฐธ์กฐ๊ฐ์ ๊ฐ์ ธ์ ๋ฐํํ๋ ํจ์์ด๊ธฐ ๋๋ฌธ์ ํด๋น ํจ์๋ฅผ ์คํ์์ผ ๋ฐํ๋ฐ์ ๊ฐ์ ์ปดํฌ๋ํธ์ ํจ์ ์ธ์๋ก ๋ฃ์ด์คฌ์ด์ผ ํ๋ค. ์ด ๊ณผ์ ๋๋ฌธ์ ref์ ์ค์ ํด๋์๋ ํจ์๋ค์ ๋ชจ์กฐ๋ฆฌ ์คํ์์ผ ์ฃผ๋ ๋ก์ง์ผ๋ก ์์ฑํ์๋ค. ์ํ์ ์ผ๋ฐ ํจ์๋ฅผ ๋ฐ๋ก ๊ตฌ๋ถํ ์๋ ์๊ธฐ ๋๋ฌธ์ด๋ค.
๋ฐ๋ผ์ ์ด๋ฅผ ์ด๋ป๊ฒ ํด๊ฒฐํ๋ฉด ์ข์๊น ์๊ฐํ๋ค๊ฐ ํด๋ผ์ด์ธํธ์์ ํจ์๋ฅผ ์ฃผ๋ ๋ฐฉ์์ ๋ฐ๊ฟ๋ณด๋ฉด ๋์ง ์์๊น ์๊ฐํ๋ค.
// ๋ณ๊ฒฝ ์
<TodoList
todoList={todoList}
fetchData={fetchData}
/>
// ๋ณ๊ฒฝ ํ
<TodoList
todoList={todoList}
fetchData={() => {
return fetchData;
}}
/>๊ธฐ์กด์๋ ํจ์ ์์ฒด๋ฅผ ๋ฃ์ด์คฌ์์ง๋ง, ์ด๋ฒ์๋ ํจ์๋ฅผ wrapper ํจ์๋ก ๊ฐ์ธ ํจ์๋ฅผ ์คํํ๋ฉด ๋ด๊ฐ ๋๊ฒจ์ฃผ๊ณ ์ ํ๋ ํจ์ ์์ฒด๋ฅผ ๋ฐํํ ์ ์๋ ํจ์๋ฅผ ์ธ์๋ก ๋๊ฒจ์ฃผ์๋ค.
fetchData ์ธ์๋ createElement ๊ณผ์ ์์ ์ฌ์ฉ์๊ฐ ์ ์ํ ์ปค์คํ
property์ด๊ธฐ ๋๋ฌธ์ props์ ref๋ก ๊ฐ๊ฒ ๋๊ณ , ์ด๋ฅผ ๊ธฐ๋ฐ์ผ๋ก fiber๋ฅผ ๋ง๋๋ ๊ณผ์ ์์ destructuringFunctionalComponentWithRef()์ ์คํ์ํค๊ฒ ๋๋๋ฐ, ํด๋น ํจ์๋ ํจ์๋ฅผ ์คํํ๋ ํจ์๊ฐ ์๋ ํจ์๋ฅผ ๋ฐํํ๋ ํจ์์ด๊ธฐ ๋๋ฌธ์ ์คํ ๊ณผ์ ์์ ์คํํ ํจ์๋ง ๋จ๊ฒ ๋์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์๋ค.
๋ฆฌ๋ทฐ ์์ฒญ
์๋ ํ์ธ์ ๋ฉํ ๋! ๊ณ ์ ๋ง์ผ์ญ๋๋คใ ใ
๋ถ์กฑํ์ง๋ง ํด๋ผ์ด์ธํธ๋ ๋ฒ๋ค๋งํ ํ์ผ์ ๋ณด๋ด๋๋ก ํด์ ๋ฐฐํฌํ์ต๋๋ค! https://asia-northeast3-todo-24f54.cloudfunctions.net/api/
์ค๋ ์ง๋ฌธ๋๋ฆฌ๊ณ ์ถ์ ๊ฒ์ด ํ๊ฐ์ง๊ฐ ์์ต๋๋ค. ํ์์ผ ๋ฆฌ๋ทฐ์์ ๋ฉํ ๋๊ป์ ์ปค์คํ ์ด๋ฒคํธ๋ฅผ ๋ง์ํด์ฃผ์ ์ ์ปค์คํ ์ด๋ฒคํธ์ ๋ํด์ ์กฐ๊ธ ์ฐพ์๋ณด์์ต๋๋ค.
// CustomEvent ์์ฑ
const catFound = new CustomEvent("animalfound", {
detail: {
name: "cat",
},
});
const dogFound = new CustomEvent("animalfound", {
detail: {
name: "dog",
},
});
// ์ ํฉํ ์ด๋ฒคํธ ์์ ๊ธฐ ๋ถ์ฐฉ
obj.addEventListener("animalfound", (e) => console.log(e.detail.name));
// ์ด๋ฒคํธ ๋ฐ์ก
obj.dispatchEvent(catFound);
obj.dispatchEvent(dogFound);
// ์ฝ์์ "cat"๊ณผ "dog"๊ฐ ๊ธฐ๋ก๋จ
์ด๋ฐ ์์ผ๋ก Custom Event์ ๋ํด์ ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ์์ฑํ ๊ฐ์ฒด๋ฅผ dispatchEvenet๋ฅผ ํตํด ์ด๋ฒคํธ๋ฅผ ๋ฐ์กํ๋ฉด ํด๋น ์ปค์คํ ์ด๋ฒคํธ๋ฅผ ๊ตฌ๋ ํ ๊ณณ์ ํด๋น ์ด๋ฒคํธ๋ฅผ ์คํํ๋ ๋ฐํ-๊ตฌ๋ ํจํด์ ๋ฎ์๋ค๊ณ ์๊ฐํฉ๋๋ค.
์ฌ์ญค๋ณด๊ณ ์ถ์ ๊ฒ์ ์ด๋ฌํ ์ปค์คํ ์ด๋ฒคํธ๊ฐ ํ์ ์์ ๋ง์ด ์ฐ์ด๋์ง ๊ถ๊ธํฉ๋๋ค. ์ ๋ ์ด์ ๊น์ง ํ๋ฒ๋ ์ฌ์ฉํด๋ณธ ์ ์ด ์์ด์ ์์ํ ๊ฐ๋ ์ด๊ธฐ๋ ํ์ง๋ง, ๋ฐํ-๊ตฌ๋ ๊ณผ ๋น์ทํ ํจํด์ ํตํด ์ ์ญ์์ ๊ด๋ฆฌํ ์ ์๋ ์ฅ๋ฐ๊ตฌ๋๊ฐ์ ๊ธฐ๋ฅ๊ณผ ๊ฐ์ ๊ณณ์์ ์ ์ฉํ ๊ฒ ๊ฐ๋ค๊ณ ์๊ฐํฉ๋๋ค. ํ์ ์์๋ ์ด๋ฅผ ํ์ฉํ๋์ง, ํ๋ค๋ฉด ์ด๋ค ์์ผ๋ก ํ์ฉํ๋์ง ๊ถ๊ธํฉ๋๋ค!
๋ฒ์จ ๋ง์ง๋ง ๋ฆฌ๋ทฐ๋ค์,,๐ฅฒ ์ด์ ๊น์ง ์ ๊ฐ ๊ผผ๊ผผํ๊ฒ ์๊ฐํ์ง ๋ชปํ๋ ๊ฒ๋ค์ ๋ง์ด ์ง์ด์ฃผ์ ์ ์ ๋ง์ ์ํฐํจํด์ ๋ฐ๊ฒฌํ ์๋ ์์๋ ์๊ฐ์ด์๋ ๊ฒ ๊ฐ์ต๋๋ค. ํญ์ ์ ์ฑ๋ค์ฌ ๋ฆฌ๋ทฐํด์ฃผ์ ์ ์ ๋ง ๊ฐ์ฌํฉ๋๋ค!