리액트

리액트에서 form의 작동 (feat.FormData와 JSON)

always_yoki 2023. 6. 25. 18:27

 

어제, 리덕스로 로그인상태를 관리하는데에 성공했다.

그리고 게시글 작성할때 작성자 정보를 추가해서 전송하기 위해 로직을 변경했다.

 

그 과정을 통해 생각해보면 당연하지만 겪기 전에는 생각하지 못했던 부분을 다시 한번 학습할 수 있었다.

 

 

기계적인 코딩 금지!

 

 

첫번째, <form>

 HTML의 form과 input은 사실 너무 당연하게 쓰고있어서 오히려 작동원리를 생각하지 않게 된달까? (나만 그래?)

다양한 input태그로 수집된 사용자의 선택 정보들은 submit될때 form 요소의 action 속성에 지정된 URL로 HTTP 요청이 생성된다.   폼이 전송되면 브라우저는 자동으로 HTTP 요청을 만들어 전송한다. 원래는 그렇다.

 

그러나, 리액트 클라이언트 사이드에서 작동하는 라이브러리기 때문에, 백엔드가 없는 상태에서는 서버에서 HTTP 요청을 처리할 수 없다. 서버가 있다면야 서버가 HTTP요청을 받고, 요청을 처리해서 다시 클라이언트에게 응답을 보내줄테지만, 클라이언트에서 처리를 해주기 위해서는 폼이 전송되면서 발생하는 기본적인 '새로고침' 현상을 event.preventDefault()로 막은 다음, 로직을 따로 작성해줘야 한다. 이벤트 핸들러를 작성하는 것이다.

 

비교를 해보자. 지난 팀프로젝트였던 스프링부트 애플리케이션에서는

 

 

<input type="submit" value="등록" formaction="/kidsaccount/AddProfile">

 

 

이렇게 formaction에 url 경로를 지정해주고 컨트롤러에서 url 경로를 받아온 다음,  로직을 처리해주었다.

 

그리고 리액트 애플리케이션에는

 

<form method="POST" onSubmit={posting}>

 

 

이렇게 onSubmit 이벤트를 따로 작성해서 클라이언트 측에서 모든 작동이 일어나게 해야한다.

posting 이라는 이름으로 작성한 이벤트 핸들러에서 데이터를 가공한 다음 fetch API를 사용해서 서버로 전송하는 방식이다. 리액트 라우터 라는 라우팅 라이브러리를 자유자재로 사용할 수 있다면 라우터가 공유하는 데이터를 활용해 여러가지 방법으로 데이터를 다룰 수 있을 것 같은데, 그건 다음스텝에서  고민 해보는걸로..찡긋😉

 

아무튼, 이러이러한 이유로 리액트에서는 form이 작동하는 방식인, input 데이터를 자동으로 감지해서 서버로 요청을 보내주는 시스템을 이용할 수가 없다..!  물론 리액트 라우터의  <Form> 컴포넌트를 사용해서 엇비슷하게 사용은 가능하다.

 

필자도 처음에  Form 컴포넌트를 이용해서 서버로 전송했었다. 그런데 그렇게 되면 오로지 사용자 화면에서 수집하는 input의 데이터만 action으로 전송해줄 수 있어서, 리덕스로 받아온 사용자 정보를 같이 포함시킬 수가 없었다. 

 

그래서  hidden속성의 input 태그에 value 값을 주어 같이 전송하는 방법으로 츄라이했는데, 그렇게 하면 언컨트롤 데이터를 컨트롤 하게 사용하는거라고... 콘솔창에서 시뻘건 경고창이 잔뜩 날아들어서 그냥 <Form>과 action을 포기하는 걸로 결정. 

 

게시글 목록과 같은 다른 컴포넌트에서는 리액트 라우터의 loader를 통해 데이터를 받아오는데 그렇게 하면 하위 컴포넌트에서도 useLoaderData를 통해 데이터를 공유할수 있어서 좋다. 그러나 게시글 작성 컴포넌트에서는 post만 잘 하면되니까 굳이 욕심부리지 않아도 될듯 했다.

 

 

두번째. formData

결과적으로, Form을 form으로 바꾸고 state들을 만들어 사용자가 입력하는 값을 저장한 다음,

FormData 객체를 만들어 append로 키값으로 묶어 넣어줬다.

그리고 신나게 fetch로 POST를 보냈는데....값이 안들어가...! (통신은 되는데)

 

 

 

 

 Postman으로 post 보내봤는데도 값이 들어가지 않았다. append가 안된걸까? 그럴리 없는데.

 

알고보니,  JSON 서버로  호스팅한 서버가 formData의 값을 읽어들이지 못하기 때문이였다.

 formData는 HTTP 요청을 보낼때 body에 자기가 가진 폼데이터를 인코딩해서 전송을 하는데

JSON server는 Formdata를 직접 처리가 할 수 없다는 것이다. 그렇기때문에 formData 객체를 처리하려면 객체안에 저장된 키 값 쌍을 자바스크립트 객체로 다시 변환해서 JSON.stringify() 로 JSON 문자여로 변환해서..보내야한다는..

그럼 굳이 formData 객체를 쓸 필요도 없이 그냥 state를 모아서 객체로 묶어 넘겨줘도 되는건디? ㅎㅎ

 

리액트 라우터의 <Form> 컴포넌트를 사용할때는 action을 타고 formData로 수신이 되니까 formData로 받아와서 JSON으로 보내주는거였는데, 이걸 바꾸는 과정에서 작동방식을 깊게 고민하지 않고 냅다 코드만 바꾸니까 혼란이 생긴 것이다아.

 

앞으로는 코드를 바꾸기 전에 먼저 머리로 시뮬레이션을 충분히 돌려봐야겠다.