Notice
Recent Posts
Recent Comments
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
Tags more
Archives
Today
Total
관리 메뉴

HYEWON JUNG의 개발일지

20231115 TIL Fan Letter -3 상세페이지 수정 삭제 구현 본문

개발일지

20231115 TIL Fan Letter -3 상세페이지 수정 삭제 구현

혜won 2023. 11. 16. 09:09

목표

  • styled component 적용 
  • detail 수정 삭제 구현
  • 이미지 디폴트 넣기
  • drilling 리팩토링 후 context 넘어가기

새로 알게 된것/ 오늘의 코드

상세페이지 버튼 기능 구현

현재 drilling 구조

1번째 삽질 

<li style={fanLetterStyle} key={letter.id} onClick={()=>{navigate(`/${letter.id}`) {state:letters}}}>

navigate로 data 내려주기 

const {state} = useLocation()

Detail에서 data 받기

const [detail, setDetail] =useState(state)

  const removeLetterBtnEvent = (id) => {
      const filteredLetter = letters.filter(to => to.id !== id)
      setDetail(filteredLetter)
}

새롭게 state를 준 후 초기값에 navigate로 받아온 letters(state)를 넣어줬다.  그리고 삭제 기능 넣고 실행을 하면 아무것도 바뀌지 않는다. 

 console.log(filteredLetter)를 해보면 datail의 데이터에서 삭제되는 것을 볼 수 있었다. 

 

안되는 이유는 조금만 생각해도 알 수 있었다. 

state를 새로 선언하고 그 state를 set해준 것이기 때문에 Letters에 있는 letters state에는 아무런 변화가 생기지 않는 것은 당연하다. 

 

2번째 삽질 (성공)

<li style={fanLetterStyle} key={letter.id} onClick={()=>{navigate(`/${letter.id}`) {state:letters} {setLetters: setLetters}}}>

 

안 될 것은 예상했지만 마지막 발악으로 해봤다. 

setLetter is not a function 에러가 뜬다. setLetter는 안끌어와졌다.

 

타이밍 좋게 튜터님과 면담이 생겨서 여쭤봤다.

튜터님 :"가장 상위 컴포넌트인 App에서 state를 선언하고 내려주는 것은 어떨까요?" 

나: '와 천재신가..? 아님 내가 멍청인가?'

Detail보다 상위요소에서 props drilling이 시작되면 Detail에서 받을 수 있는 것이 당연한데 왜 생각을 못했을 까? 

 

이실직고하면 너무 멍청하게도 

이렇게 Detail의 상위 요소가 없다고 생각해버렸다.. 와우.. 완전히 이해를 잘못하고 있던 상태였던 것이다. 지금 생각하면 너무 바보같이 생각한 것 같다.

 

Router 에서 Home을 옮겨지는  Route로직을 잘 이해했더라면 이런 일이 생기지 않았을 텐데.. 

아무튼 이제라도 이해하고 넘어가서 다행이다!

이렇게 drilling을 수정해주고 삭제 버튼을 구현 했더니 !

  const removeLetterBtnEvent = (id) => {
      const filteredLetter = letters.filter(to => to.id !== id)
      setLetters(filteredLetter)
}

오류 빠밤!

이건 조금 곰곰히 생각해보면 문제점을 알 수 있다.

버튼을 눌렀을 때 삭제되면서 일어나는 과정을 보면

1. 버튼을 누른다

2. 필터된 값이 나오면서 해당 데이터가 사라진다.

3. 우리는 아직 그 id의 detailpage에 있다.

4. 그 id의 data는 사라졌기에 읽힐 것이 없다. 

이렇기에 그 페이지에 머물러 있으면 오류가 나는 것은 당연하다. 버튼을 클릭하면 다시 Home으로 가는 로직도 포함되어야한다. 

  const navigate = useNavigate()

  const removeLetterBtnEvent = (id) => {
    if(window.confirm("정말로 지우시겠습니까?")){
      const filteredLetter = letters.filter(to => to.id !== id)
      setLetters(filteredLetter)
      navigate(`/`)
    }else{
      alert("취소되었습니다")
    }
}

하는 겸에 확인 절차로 추가했다.

삭제가 잘 이루어지는 것을 볼 수 있었다.! 어제 하루종일 이것때문에 진도를 못나갔는데 사실은 1시간만에 끝낼 수 있었다니.. 코드를 넓게 보는 사고가 필요하다!! 

 

수정기능 구현하기

완성본을 미리 보자면.

 

수정 버튼을 누르면 p태그가 textarea로 바뀌면서 입력할 수 있게 변경이 된다. 그 후 textarea에서 입력한 값이 p태그에 반영이 될 수 있게 되야한다. 

 

그래서 state 가 2개가 추가로 필요하다!

  const [isEdit, setIsEdit] = useState(false)
  const [editLetter, setEditLetter] = useState(foundLetter.content)

isEdit은 수정상태인지 아닌지 에 따라 textarea인지p태그 인지 구분해야하니 필요하고 editLetter는 textarea에서 수정한 것을 반영하기 위해서 필요하다!

 

isEdit상태에 따라 달라지는 것은 두개가 있는데 위에서 말했듯 textarea 랑p태그 , 버튼이 수정중일 땐 수정완료버튼이 뜨고 아닐땐 수정, 삭제가 뜨게 하는 것이다.

우선 textarea , p부터

const editTextHandler = (event) => { setEditLetter(event.target.value) }

{
isEdit ?
<textarea value={editLetter} onChange={editTextHandler}>{foundLetter.content}</textarea> :
<p>{foundLetter.content}</p>
}

textarea에 input이랑 똑같이 value와 onChange를 넣어주면 된다.  삼항 연산자로 isEdit의 상태가  true일경우  textarea를 false일 결우 p를 나타내게 하고 내용은 동일하게 들어가면된다. 

그리고 버튼의 경우 동일한 방법인데

{isEdit ? <button onClick={() => (finishEditHandler(foundLetter.id))}>수정완료</button> : <div>
 <button onClick={() => { setIsEdit(!isEdit) }}>수정</button>
 <button onClick={() => (removeLetterHandler(foundLetter.id))}>삭제</button>
</div>}

수정완료 버튼의 기능은 

  const finishEditHandler = (id) => {
    const editcontent = letters.map((item) => ({
      ...item, content: item.id === id ? editLetter : item.content
    }))
    if (editLetter === foundLetter.content) {
      alert("수정된 부분이 없습니다.")
    } else {
      setLetters(editcontent)
      setIsEdit(false)
    }
  }

map돌려서 id체크하고 맞으면 content 부분에 수정된 내용이 들어가고 id가 다른 것들은 그대로 각자의 content를 가진다. 

 

만약 수정된 글과 이전글이 동일 할 경우  alert를 띄우고 아니면 setLetters를 편집된 레터로 넣어주고  isEdit상태로 false로 만들어주면 된다. 

 

목표 달성여부

  • styled component 적용 
  • detail 수정 삭제 구현
  • 이미지 디폴트 넣기
  • drilling 리팩토링 후 context 넘어가기

내일 목표

  • styled component 적용 
  • 이미지 디폴트 넣기
  • drilling 리팩토링 후 context 넘어가기