-
Notifications
You must be signed in to change notification settings - Fork 39
[이태경] Sprint9/Refactor #244
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
The head ref may contain hidden characters: "Next-\uC774\uD0DC\uACBD-sprint9-r"
Changes from all commits
f2cef3d
359eb74
50c13b8
fd14335
2bf93df
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 서버 액션을 사용해봤습니다. 파일 위치가 app 폴더 내에 있는게 좀 이상한거 같긴 한데, 공식 문서에서도 app 폴더 내에 위치하고 있어서 여기에 생성을 했습니다. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| "use server"; | ||
|
|
||
| import { revalidateTag } from "next/cache"; | ||
|
|
||
| import { createTodoItem } from "@/features/todo/services/todoApi"; | ||
|
|
||
| export async function createTodoItemAction(_: any, formData: FormData) { | ||
| const name = formData.get("name")?.toString(); | ||
|
|
||
| if (!name) return; | ||
|
|
||
| try { | ||
| const data = await createTodoItem(name); | ||
|
|
||
| revalidateTag("todoList"); | ||
|
|
||
| return data; | ||
| } catch (err) { | ||
| console.log(err); | ||
| return; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,23 +1,24 @@ | ||
| "use client"; | ||
|
|
||
| import DoneEmpty from "@/features/todo/components/DoneEmpty"; | ||
| import { startTransition, useOptimistic, useRef } from "react"; | ||
|
|
||
| import DoneEmpty from "@/app/_components/Empty/DoneEmpty"; | ||
| import TodoEmpty from "@/app/_components/Empty/TodoEmpty"; | ||
| import TodoContent from "@/features/todo/components/TodoContent"; | ||
| import TodoEmpty from "@/features/todo/components/TodoEmpty"; | ||
| import { updateTodoItem } from "@/features/todo/services/todoApi"; | ||
| import { TodoItemType } from "@/types/todoTypes"; | ||
| import { startTransition, useEffect, useOptimistic, useState } from "react"; | ||
|
|
||
| interface Props { | ||
| data: TodoItemType[]; | ||
| onUpdate?: (id: number) => void; | ||
| } | ||
|
|
||
| const TodoListArea = ({ data }: Props) => { | ||
| const [todoAll, setTodoAll] = useState(data); | ||
| const initialDataRef = useRef<TodoItemType[]>(data); | ||
| const [optimisticState, toggleOptimisticState] = useOptimistic< | ||
| TodoItemType[], | ||
| number | ||
| >(todoAll, (currentState, id) => { | ||
| >(initialDataRef.current, (currentState, id) => { | ||
| return currentState.map((todo) => | ||
| todo.id === id ? { ...todo, isCompleted: !todo.isCompleted } : todo | ||
| ); | ||
|
Comment on lines
+17
to
24
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 말씀하셨던대로 useOptimistic의 초기값을 data로 설정했지만 여전히 이전 데이터로 돌아가더라구요....
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ㅎㅎ 제가 이 문제를 전체 코드베이스 훑어보며 좀 파보니까, 구조적으로 이런 문제가 있더라고요
결론적으로 이 문제는 서버 컴포넌트의 리렌더링 때문에 발생하는 현상입니다. 예를 들면 const TodoListArea = ({ data }: Props) => {
// 클라이언트 상태로 서버 데이터 관리
const [clientData, setClientData] = useState(data);
...이런식으로 클라이언트 상태로 서버 데이터를 관리하는게 부가적으로 필요할것같고, 결과를 보면 이전에 태경님이 생각하셨던 방식과 비슷하게 풀어가는게 좋을 것 같아요. 한번 참고해보시고, 더 좋은 방법이 있을지 고민해보세요! |
||
|
|
@@ -28,30 +29,23 @@ const TodoListArea = ({ data }: Props) => { | |
| // 낙관적 업데이트 | ||
| toggleOptimisticState(id); | ||
|
|
||
| const targetCheck = todoAll.find((todo) => todo.id === id)?.isCompleted; | ||
| const targetCheck = optimisticState.find( | ||
| (todo) => todo.id === id | ||
| )?.isCompleted; | ||
| const updateData = { isCompleted: !targetCheck }; | ||
|
|
||
| const prevTodoAll = todoAll; | ||
|
|
||
| try { | ||
| setTodoAll((prevTodoAll) => | ||
| prevTodoAll.map((todo) => | ||
| todo.id === id ? { ...todo, isCompleted: !todo.isCompleted } : todo | ||
| ) | ||
| ); | ||
| await updateTodoItem(id, updateData); | ||
| const updateTodo = initialDataRef.current.map((todo) => | ||
| todo.id === id ? { ...todo, isCompleted: !todo.isCompleted } : todo | ||
| ); | ||
| initialDataRef.current = updateTodo; | ||
| } catch (error) { | ||
| console.error(error); | ||
|
|
||
| setTodoAll(prevTodoAll); | ||
| } | ||
| }); | ||
| }; | ||
|
|
||
| useEffect(() => { | ||
| setTodoAll(data); | ||
| }, [data]); | ||
|
|
||
| const todoData = optimisticState.filter((item) => !item.isCompleted); | ||
| const doneData = optimisticState.filter((item) => item.isCompleted); | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/src/features/todo/components → /src/app/_components/Empty 이동되었습니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
네, 만약 공용 폴더라면 app 바깥에 components 폴더를 만들어 유지해주시고,
특징 라우트그룹/ 페이지에서만 쓰이는 컴포넌트라면 이렇게 유지해주시면 될것같아요 :)