❗️Error/오류를 해결하자!

토이프로젝트 ) 리액트 모달창에서 사진 수정하기, 수정 없이 모달 창 닫으면 해당 데이터만 보이는 에러 해결하기

hellohailie 2022. 7. 23. 03:05

문제점 1. 업데이트 하는 Modal 부분에서 사진 수정이 안된다. (미리보기도 안되고, 서버한테 사진 데이터 못넘겨줌)

 

기존 코드

//Modal.js

const [photo, setPhoto] = useState(data.photo);

 // const photoUpdateHandler = (event) => {
  //   let fileInput = false;
  //   if (event.target.files[0]) {
  //     fileInput = true;
  //   }
  //   if (fileInput) {
  //     try {
  //       Resizer.imageFileResizer(
  //         event.target.files[0],
  //         150,
  //         150,
  //         "png",
  //         90,
  //         0,
  //         (uri) => {
  //           setPhoto(uri);
  //         },
  //         "base64",
  //         180,
  //         180
  //       );
  //     } catch (err) {
  //       console.log(err);
  //     }
  //   }
  // };
...

return (
... 
<input
	type='file'
/>
<img src={data.photo} alt='' />

기존 코드 해석 => 바로 위의 부모 파일로부터 전체 데이터를 받아오고, return을 <img src={data.photo} alt='' /> 이런 식으로 이미지를 지정해 주었다. 

 

 

수정 코드

//Modal.js

const [photo, setPhoto] = useState(data.photo);

const photoUpdateHandler = (event) => {
    let fileInput = false;
    if (event.target.files[0]) {
      fileInput = true;
    }
    if (fileInput) {
      try {
        Resizer.imageFileResizer(
          event.target.files[0],
          150,
          150,
          "png",
          90,
          0,
          (uri) => {
            setPhoto(uri);
          },
          "base64",
          180,
          180
        );
      } catch (err) {
        console.log(err);
      }
    }
  };
...

return (
... 
<input
	type='file'
    onChange={(e) => photoUpdateHandler(e)}
/>
<img src={photo} alt='' />

 

수정 코드 해석 => 

현재 state 값인 photo를 넣어서 return 부분에는 <img src={photo} alt='' /> 이렇게 코드를 바꾸었다. 

그리고 사진을 수정하는 버튼을 누를 때 데이터를 보내줘야지 렌더링이 되서 사진 데이터가 들어간다.

 <input type='file' onChange={(e) => photoUpdateHandler(e)} />

 

 

알게 되고, 배운 점

버튼을 누를 때 값을 요한다면 데이터를 넣어주자!!!!!!


 

문제점 2. 유저가 수정하려다가 마음이 변해서 그냥 모달창 닫으면 수정 버튼 누른 게시글만 뜬다.

 

기존 코드

//
Data.js

function Data({ data, setData /*onChangeSelectedDiary*/ }) {
...

const updateBtnHandler = async (dataId) => {
    setData(data.filter((el) => el.id === dataId.id));
  };
  
...

return (
<Modal
	data={data}
	 setData={setData}
	updateBtnHandler={data}

기존 코드 해석 => 부모인 App.js에서 props로 전달 받은 전체 데이터인 data와 setData에 직접 상태를 변경하고 있다. 

즉, 유저가 업데이트를 하려고 모달창을 여는 버튼을 눌렀을 때 전체 데이터를 바꾸고 있다. 

 

 

수정 코드

// Data.js

const [modalData, setModalData] = useState([]);

...
const updateBtnHandler = async (dataId) => {
    setModalData(data.filter((el) => el.id === dataId.id)[0]);
  };
  
 ...
  
 return (
 
 <Modal
	data={modalData}
	setData={setData}
/>

 

수정 코드 해석 => 

이전 코드에서 유저가 업데이트를 하려고 모달창을 여는 버튼을 눌렀을 때 전체 데이터를 바꾸고 있어서

updateBtnHandler에서 필터한 데이터를 담을 state를 따로 만들었다. 모달창에서 변경한 데이터를 set함수에 다시 값을 넣어주니까 모달에는 전체 데이터에서 바꾸는 게 아니라 따로 상태를 만들어서 관리해야한다. 

 

** 참고로 setModalData는 Data 컴포넌트에서 모달에 넘길 데이터만 지정하는 함수라 Modal에 props로 딱히 넘길필요가 없다.

 

 

 

updateBtnHandler 함수는 모달창 안에 해당하는 데이터가 맞게 들아가라고 써준 함수인데, 

setModalData 안에 [0]을 써주지 않는다면 알맞은 값이 들어가지 않는다. 

setModalData(data.filter((el) => el.id === dataId.id));

라면

현재 값인 modalData 를 콘솔에 찍어보면 id가 4인 값만 나오게 된다. 

 

setModalData(data.filter((el) => el.id === dataId.id)[0]);

일때 비로소

 

여기서 modalData 를 콘솔에 찍어보면 id가 클릭한 값만 나오게 된다. 

사실 원리는 잘 모르겠다.. 구글링 필요!

 

알게 되고, 배운 점

필터링 할때 [0] 을 써야하는지 보기.

Data 컴포넌트에서 App 에서 받아온 전체 데이터가 모달창을 여는 순간! 필터가 작동해버린다. 

수정 완료를 하면 전체 데이터가 다시 오는데, 수정 완료 버트를 안누르고 모달 창을 닫아버리니까 하나만 남아있던 것이다. 

 

모달창을 구현할 때는 필터한 데이터를 담을 state를 따로 만들어주자!

 

 


문제점 3. 위처럼 코드를 수정하고 모달창에서 '수정완료' 버튼을 누르면 콘솔창에는 올바른 데이터가 나타나지만 엄청 빨리 떴다가 사라진다. 

 

수정 코드

//Modal.js

const Modal = ({ data, setData }) => {

...

const updateSubmitHandler = async (e,id) => {
    e.preventDefault();
    // console.log(id);
    if (story.trim().length === 0) {
      return;
    }
    const inputData = {
      date: new Date(date),
      weight: weight,
      photo: photo,
      exercise: exercise,
      story: story,
      id: id,
    };
    //console.log(inputData);
    const updateResponse = await axios.patch("/data", inputData);
    setData(updateResponse.data);
  };
  
  ...
  
 return (
    <form
      onSubmit={(e) => {
        updateSubmitHandler(e, data.id);
      }}
    >

 

수정 코드 해석 => 

form 안에 submit 역할을 하는 버튼인 '수정하기' 버튼을 누름과 동시에 새로고침 (새로 실행) 하지 않게 하고 싶은 경우에는 

event.preventDefault()

를 사용해야한다. 

 

그런데 이 때, 나는 수정하기 버튼을 누를 때, 즉 submit 이 작동할 때 updateSubmitHandler 함수에 이미 data.id 값을 보내고 있으니까,

id.preventDefault();

이런식으로 코드를 짰는데 이건 아무런 효과가 없었다. 

이를 해결하기 위한 방법으로는 updateSubmitHandler 함수에 event 값과 data.id 값을 동시에 보내줘서 해결하는 방법이 있다!

 

 


문제점 4. 그런데 위처럼 코드를 수정하면 모달창이 닫히지 않는 에러가 나타난다. 

이를 해결하기 위해서는 

 

수정 코드 

//Data.js

return (

 <Modal
	data={modalData}
	setData={setData}
	// updateBtnHandler={data} => 이건 굳이 안내려도 된다. 왜냐면 data={modalData}와 중복이니까
	setIsOpen={setIsOpen}
	/>

모달창을 열고 닫힘 상태를 관리하는 setIsOpen 를 Modal에 props로 전달해준다.

 

 

 

// Modal.js

const Modal = ({ data, setData, setIsOpen /*updateBtnHandler*/ }) => {

...

const updateSubmitHandler = async (e, id) => {
    e.preventDefault();
    // console.log(id);
    if (story.trim().length === 0) {
      return;
    }
    const inputData = {
      date: new Date(date),
      weight: weight,
      photo: photo,
      exercise: exercise,
      story: story,
      id: id,
    };
    //console.log(inputData);
    const updateResponse = await axios.patch("/data", inputData);
    setData(updateResponse.data);
    setIsOpen(false);
  };

 

그리고 위와 같이 수정 완료시에 setIsOpen 를 false라고 모달창을 닫아준다. 

 


* 위의 4가지 문제를 해결하면 모달창이 2개 뜨는 에러가 해결되는데 내가 생각하는 해결 방법은아래와 같다. 

 

수정 코드

//Data.js

return (

 <Modal
	data={modalData}
	setData={setData}
	// updateBtnHandler={data} => 이건 굳이 안내려도 된다. 왜냐면 data={modalData}와 중복이니까
	setIsOpen={setIsOpen}
	/>

 

updateBtnHandler={data} 이 코드를 주석처리 했다.

왜냐면 위에서 data={modalData}로 데이터를 props로 내려주고 있는데 중복이니까

 


⭐️새로 배운 점 ⭐️ 고화질 사진이 용량 제한에 걸려 안올라간다면!

기본 디폴트 용량이 작게 잡혀있는 것을 수정해주면 된다. 

 

//server.js

app.use(express.json({limit: "10mb"}));

~~ 크기까지 지원해준다고 한다. 

 

 


ps) 에러 해결을 위해 코드 리뷰해준 동기님께 감사의 인사를 드립니다. 

 

😃 잘못된 개념 전달이 있다면 댓글 부탁드립니다. 저의 성장에 큰 도움이 됩니다🤓