모달 만들기

jew·2024년 5월 29일

zustand

목록 보기
2/2
post-thumbnail

전에 만들었던 모달은 차력쇼로 하나 하나 만들었어서, 이번에는 상태관리도 붙이면서 좀 생각해보면서 만들고 싶어서 방법을 고민해봤다

task를 작성하는 모달을 가지고 어떻게 해야할지 먼저 생각해봤는데, 전에 만들때 구글링했던 모양새들은 alert를 위한 모달들이라 open의 boolean 값만 구분하면 되었던 것만 기억났다

일단 task를 작성하는 액션에 타입으로 boolean값을 부여하고 액션의 boolean 값에 따라 모달을 보여주기로 정했다.

흐름은 이런 느낌 ...

Create
작성하기 클릭 -> 모달 open ->
모달 내에서 task(title, detail) 작성 후 제출하기 버튼 클릭 ->
모달 close, 작성된 task가 /today 페이지의 컴포넌트 todo.tsx에서 작성 순서대로 목록이 보여짐

Read
todo.tsx에 보여진 목록 중 하나를 선택 ->
선택된 task이 모달로 open(title, detail)되고 모달에 삭제하기/수정하기 버튼이 함께 있음 ->
이때 A task가 모달로 열려있는 상태로 B task를 클릭하면 열려있던 모달의 내용만 바뀜 ->
닫기 버튼 누르면 닫힘

Update
read 중에 수정하기 버튼 ->
선택한 글의 title/detail이 그대로 있으면서 taskForm 활성화(id, title, detail 전달) ->
제출하기 -> 목록 위치 그대로 내용만 수정됨 (미완)
그리고 모달 close

Delete
read 중에 삭제하기 버튼 -> task의 id 받아와서 삭제 그리고 모달 close

task를 add하고 show해주는 것까지는 어렵지 않았는데, 의식의 흐름대로 코드를 작성하다보니 로직이 꼬여서 ㅋㅋ...

1

일단 useModalState와 task에 적용할 액션 함수가 담긴 useTaskStore로 분리했다.

모달의 상태별 모달 액션이 담길 useModalState는 하단의 블로그를 참고해서 작성했다.

https://youth-dev-log.vercel.app/blog/modal-global-state-management-using-zustand

task에 적용할 액션 함수들은 supabase DataBase - view table - API Docs를 통해 쉽게 찾아볼 수 있었다~!!

useTaskStore에서 유저의 todolist table 데이터를 fetch해오고, todolist table에 crud할 함수를 작성했다.

import { create } from 'zustand'

export const useTaskStore = create<TodoState>(set => ({
  tasks: [],
  fetchTasks: async () => {
    const { data, error } = await supabase.from('todolist').select()
// 에러처리
      set({ tasks: data })
    
  },
  createTask: async (title, detail, userId) => {
    const { data, error } = await supabase
      .from('todolist')
      .insert([{ todo_title: title, todo_detail: detail, user_id: userId }])
      .select()
// 에러처리
      set(state => ({ tasks: [...state.tasks, ...data] }))
  },
 
/* 너무 길어져서 생략.. 
  
  밑은 editTask, deleteTask 함수 */

2

그리고 Modal과 Modal 내에서 task를 작성할 Form을 분리했다.

// Modal

const Modal = ({ children }: ModalProps) => {
  const addTaskOn = useAddTaskModalState()
  const viewTaskOn = useViewTaskModalState()
  const { changeModalState } = useModalActions()

  if (!addTaskOn && !viewTaskOn) return null

  return (
    <div>
      <div>Task</div>
      <button>closebutton</button> 
        <div>{children}</div>
    </div>
  )
}

export default Modal
// taskform

const TaskForm = ({ initialTitle = '', initialDetail = '', taskId = null }: TaskFormProps) => {
  const { changeModalState } = useModalActions()

  const createTask = useTaskStore(state => state.createTask)
  const editTask = useTaskStore(state => state.editTask)

  const [title, setTitle] = useState(initialTitle)
  const [detail, setDetail] = useState(initialDetail)
  const user = useUserStore(state => state.user) // todolist 테이블 정책에 데이터 삽입시 유저의 id를 같이 확인하는 조항을 넣어서 user 정보가 필요했음

  useEffect(() => {
    setTitle(initialTitle)
    setDetail(initialDetail)
  }, [initialTitle, initialDetail])

  const handleUpdateTask = async (e: FormEvent) => {
    e.preventDefault()
    if (!title || title.length === 0) {
      alert('Task의 제목을 작성해주세요.')
      return
    }

    if (taskId) {
      await editTask(taskId, title, detail)
      changeModalState('edit')
      changeModalState('view')
    } else {
      await createTask(title, detail, user.id)
      changeModalState('add')
      changeModalState('view')
    }
    setTitle('')
    setDetail('')
  }

  return (
    <form onSubmit={handleUpdateTask}>
      // 길어서 생략
    </form>
  )
}

export default TaskForm

그리고 모달을 Todo.tsx에 붙여줬다. 여기서는 view모드인지 edit모드인지 해당 모드의 boolean값을 확인하고 값에 따라 모달의 내용을 보여준다.

+ 추가 수정사항

정확히 값을 명시하지않고 !state만 해주다가 보니 연속으로 같은 액션을 수행했을 때 모달이 자동으로 닫혀주지 않는 상황이 발생했다.

이후 !state가 아닌 boolean값을 명시해주는 방법으로 수정했다.

changeModalState('add') => changeModalState('add', true)

이런 식으로. 그래서 Todo에 있는 Btn 함수를 이런 식으로 모두 수정해줬다.

// Todo

  const addTaskBtn = () => {
    setSelectedTask(null)
    changeModalState('add', true) // 처음에는 changeModalState('add') 였음. 
    // boolean 값 명시해서 같이 넘겨주는 방식으로 변경
  }

  const viewTaskBtn = (task: Task) => {
    console.log(task)
    setSelectedTask(task)
    if (!viewTask) {
      changeModalState('view', true)
    }
  }
  const deleteTaskBtn = async (id: number) => {
    await deleteTask(id)
    setSelectedTask(null)
    changeModalState('view', false)
  }

  const editTaskBtn = () => {
    changeModalState('edit', true)
  }

길다
만들면서 생각한건

모달 만드는 거 자체보다는 만들다가 중간에 꼬여서 다시 구조를 생각하는 부분에서 더 헷갈렸던 것 같다. 생각해두지 않은 부분에서는 의식의 흐름대로 만드려고 하는 습관이 있어서, 만들다 말고 구조를 변경하는데에 고민하는 시간이 길어진다. 어떤 구조와 흐름으로 만들지 꼭 미리 정하고 시작하자

계속..
모달 백 스크롤 막기

profile
문제 있으면 의식의 흐름대로 작성하는 블.log

0개의 댓글