풀스택 리액트 토이프로젝트 수강기록 - 받아적기

Kyla Kim·2023년 4월 11일

프엔꿈나무

목록 보기
4/8
post-thumbnail

1. Client- 기본기능 구현

  • Document Fragment : 빈태그. <>, </>
    DOM트리 내부에 존재하는 게 아니라 메모리상에만 따로 존재하게 된다. DOM에다가 바로 작업을 하는 게 아니라, 본격적인 DOM 조작에 앞서 잠시 보관해두는 껍데기인 것이다. 노드 조각이라고도 한다.

원래 사용하던 npm이 아닌 yarn을 사용하여 패키징을 관리하는 것 부터 난관봉착.

sass.scss

body {
  margin: 0;
}
#__next {
  margin: 10px;
}
h1 {
  text-align: center;
  margin: 20px 0;
}
.messages {
  list-style: none;
  padding: 0;
  margin: 0;
  &__input {
    display: flex;
    width: 80%;
    max-width: 700px;
    min-width: 400px;
    margin: 0 auto 10px;
    > * {
      box-sizing: border-box;
    }
    textarea {
      padding: 10px;
      flex-grow: 1;
    }
    button {
      margin-left: 5px;
      width: 60px;
    }
  }
  &__item {
    position: relative;
    margin: 10px 0;
    padding: 15px 15px 5px;
    border-radius: 5px;
    border: solid 1px #aaa;
    h3 {
      font-size: 0.85em;
      margin: 0 0 10px;
    }
    sub {
      font-weight: normal;
      margin-left: 5px;
      vertical-align: baseline;
    }
    p {
      margin: 10px 0;
    }
    &:hover .messages__buttons {
      display: block;
    }
    .messages__input {
      width: 100%;
    }
  }
  &__buttons {
    display: none;
    position: absolute;
    text-align: right;
    right: 10px;
    bottom: 10px;
  }
}

그냥 아무것도 모르겠어서 뭘 모르겠는지도 모르겠는 상태로 시작한 강의
거기서 맞닥뜨린 두 번 째 난관

입력폼에 메시지를 입력해서 잘 나오나 확인해야되는데 류발 자꾸 저 에러메세지때문에 자동 새로고침이 돼서 확인이 안된다.

에러메세지를 열심히 잘 살펴보니

const getRandomUserId = () => UserIds[Math.round(Math.random())];

위 함수에서 Math.random() 함수가 서버와 클라이언트 사이에서 충돌이 일어난 듯 보였음.. 강의창에서는 한 번도 관련된 얘기가 없어서 질문 목록을 살펴보니 어떤 학생 분께서 홀로 해결하신 걸 발견 ... 동지애 뿜뿜쓰...

선생님께서도 '하나의 함수를 서버에서도 한 번, 클라이언트에서도 한 번 실행합니다. 함수 실행 결과가 랜덤이라 매 번 값이 달라지니 자연히 "서버와 클라이언트의 text content가 같지 않다"는 오류가 발생할 수밖에 없습니다.' 라고 답글을 다셨던디 무책임해

뭐 아무튼 Client - 프론트단에서 구현해낸 코드까지만 정리해보자면

MsgList.js


import { useState } from 'react'
import MsgItem from './Msgitem'
import MsgInput from './MsgInput'

// const UserIds = ['roy', 'jay']
// const getRandomUserId = () => UserIds[Math.round(Math.random())]

const originalMsgs = Array(50).fill(0).map((_, i) => ({
  id: i + 1,
  userId : '익명',
  timestamp: 1234567890123 + i * 1000 * 60,
  text: `${i + 1} mock text`
}))
.reverse()

const MsgList = () => {
  const [msgs, setMsgs] = useState(originalMsgs)
  const [editingId, setEditingId] = useState(null)

  const onCreate = text => {
    const newMsg = {
      id: msgs.length +1,
      userId: '익명',
      timestamp: Date.now(),
      text: `${msgs.length +1} ${text}`,
    }
    setMsgs(msgs => ([newMsg, ...msgs]))
  }

  const onUpdate = (text, id) => {
    setMsgs(msgs => {
      const targetIndex = msgs.findIndex(msg => msg.id === id)
      if (targetIndex < 0) return msgs
      const newMsgs = [...msgs]
      newMsgs.splice(targetIndex, 1, {...msgs[targetIndex], text})
      return newMsgs
    })
    doneEdit()
  }

  const doneEdit = () => setEditingId(null)
  const onDelete = (id) => {
    setMsgs(msgs => {
      const targetIndex = msgs.findIndex(msg => msg.id === id)
      if (targetIndex < 0) return msgs
      const newMsgs = [...msgs]
      newMsgs.splice(targetIndex, 1)
      return newMsgs
    })
  }

  return (
    <>
      <MsgInput mutate={onCreate} />
      <ul className="messages">
        {msgs.map(x => (
        <MsgItem 
          key={x.id} 
          {...x} 
          onUpdate={onUpdate}
          onDelete={() => onDelete(x.id)}
          startEdit={() => setEditingId(x.id)} 
          isEditing={editingId === x.id} 
        />
        ))}
      </ul>
    </>
    )
}

export default MsgList

MsgItem.js

import MsgInput from "./MsgInput"

const MsgItem = ({ id, userId, timestamp, text, onUpdate, isEditing, startEdit, onDelete }) => (
  <li className="messages__item">
    <h3>
      {userId}{' '}
      <sub>
        {new Date(timestamp).toLocaleString('ko-KR', {
          year: 'numeric',
          month: 'numeric',
          day: 'numeric',
          hour: '2-digit',
          minute: '2-digit',
          hour12: true
        })}
      </sub>
    </h3>
    
    {isEditing ? (
      <>
        <MsgInput mutate={onUpdate} text={text} id={id}/>
      </>
    ) : (
      text
    )}

    <div className="messages_buttons">
      <button onClick={startEdit}>수정</button>
      <button onClick={onDelete}>삭제</button>
    </div>
  </li>
)

export default MsgItem

MsgInput.js

import { useRef } from 'react'

const MsgInput = ({ mutate, text='' ,id = undefined }) => {
  const textRef = useRef(null)

  const onSubmit = e => {
    e.preventDefault()
    e.stopPropagation()
    const text = textRef.current.value
    textRef.current.value = ''
    mutate(text, id)
  }
  return(
    <form className="messages__input" onSubmit={onSubmit}>
      <textarea ref={textRef} defaultValue={text} placeholder='내용을 입력하세요.'/>
      <button type="submit">완료</button>
    </form>
  )
}

export default MsgInput

결국 서버랑 클라이언트 충돌로 자꾸 프론트로 보이는거 자체가 안돼서 getRandomUserId() 포기함 ㅠ

이렇게 해서 나온 결과 프론트


수정이랑 삭제까지 구현해냄

2. Server - REST API

MsgLists.js

에다가

console.log(JSON.stringify(originalMsgs))


진짜 개빡쳤는데

역시나
그래서 나는 server 폴더 안에 있는 package.jason 파일 안에 "type": "module"을 추가했더니 바로 해결됨 ..ㅎ..

악 짜증나!

profile
The only way of discovering the limits of the possible is to venture a little way past them into the impossible.

0개의 댓글