47일차(1)/React(12) : jsp 웹페이지 React 로 재작성하기 (회원가입 폼)
- signup_form.jsp React App으로 작성해보기
- App.js 전체 코드
import React from "react";
//class 속성값을 편하게 제어하기 위한 모듈(install 후 사용할 수 있다
import cn from 'classnames';
function App(){
//입력한 id, pwd, email 유효성여부를 상태값으로 관리(object)
const [valid, setValid] = React.useState({
isIdValid:false,
isPwdValid:false,
isEmailValid:false
});
//현재 입력된 id, pwd, email을 상태값으로 관리
const [input, setInput] = React.useState({
id:"",
pwd:"",
pwd2:"",
email:""
});
//입력창이 한번이라도 더렵혀졌는지 여부를 상태값으로 관리
const [dirty, setDirty] = React.useState({
isIdDirty:false,
isPwdDirty:false,
isEmailDirty:false
});
//id가 변경되었을 때 호출하는 함수
const onIdChange=(e)=>{
//현재 입력한 아이디를 읽어와서
let inputId=e.target.value;
//아이디를 한번이라도 입력하면 아이디가 더럽혀 졌는지 여부를 true 로 바꿔준다.
setDirty({
...dirty,
isIdDirty:true
});
//아이디를 검증할 정규표현식
const reg=/^[a-z].{4,9}$/;
//입력한 아이디가 정규표현식과 매칭이 되는지(통과 되는지) 확인한다.
const isMatch=reg.test(inputId);
//만일 매칭되지 않는다면
if(!isMatch){
//아이디 유효성 여부를 false로 바꾼다.
setValid({
...valid,
isIdValid:false
})
return; //함수를 여기서 끝내라
}
//2. 외부 tomcat 서버에 페이지 전환없이 전송을 하고 응답을 받는다.
fetch("http://localhost:8888/Step04_Final/users/checkid.jsp?inputId="+inputId)
.then(function(response){
return response.json();
})
.then(function(data){
//3. 사용가능한지 여부에 따라 아이디 입력란에 is-valid or is-invalid 클래스를 적절히 추가, 제거를 한다.
console.log(data);
if(data.isExist){
setValid({
...valid,
isIdValid:false
});
}else{
setValid({
...valid,
isIdValid:true
});
}
});
}
//비밀번호를 입력했을 때 실행할 함수 등록
const onPwdChange=(e)=>{
//입력한 비밀번호를 읽어와서
let inputPwd=e.target.value;
//pwd의 상태값에 반영하고
setInput({
...input,
pwd: inputPwd
});
//더렵혀 졌는지 여부를 true로 바꿔준다.
setDirty({
...dirty,
isPwdDirty:true
})
//비밀번호를 검증할 정규 표현식
const reg=/[\W]/;
//만일 정규표현식 검증을 통과하지 못했다면
const isPwdValid= !reg.test(inputPwd) ? false : true ;
setValid({...valid, isPwdValid});
//만일 비밀번호 입력란과 확인란이 다르다면
if(inputPwd != input.pwd2){
setValid({
...valid,
isPwdValid:false
})
}else{ //같다면
setValid({
...valid,
isPwdValid:true
})
}
}
const onPwdChange2=(e)=>{
//입력한 비밀번호를 읽어와서
let inputPwd=e.target.value;
//pwd2의 상태값에 반영하고
setInput({
...input,
pwd2: inputPwd
});
setDirty({
...dirty,
isPwdDirty:true
})
//비밀번호를 검증할 정규 표현식
const reg=/[\W]/;
//만일 정규표현식 검증을 통과하지 못했다면
const isPwdValid= !reg.test(inputPwd) ? false : true ;
setValid({...valid, isPwdValid});
//만일 비밀번호 입력란과 확인란이 다르다면
if(inputPwd != input.pwd){
setValid({
...valid,
isPwdValid:false
})
}else{ //같다면
setValid({
...valid,
isPwdValid:true
})
}
}
//이메일을 입력했을 때 호출되는 함수
const onEmailChange = (e)=>{
let inputEmail=e.target.value;
setDirty({
...dirty,
isEmailDirty:true
})
//이메일을 검증할 정규 표현식
const reg=/^[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*.[a-zA-Z]{2,3}$/i;
//만일 입력된 이메일이 정규표현식 검증을 통과하지 못했다면
const isEmailValid = !reg.test(inputEmail) ? false : true;
setValid({...valid, isEmailValid});
}
//폼에 handleSubmit 이벤트가 일어나면 호출되는 함수
const handleSubmit=(e)=>{
//여기서 e는 react가 넣어주는 event 객체이기 때문에 원래 event 객체와는 좀 다르다.
//폼 유효성 여부를 알아내서
let isFormValid = valid.isIdValid && valid.isPwdValid && valid.isEmailValid;
//만일 폼이 유효하지 않으면
if(!isFormValid){
//기본 이벤트(원래는 폼이 전송되는 것)을 막아버린다.
e.preventDefault();
}
}
return(
<div className="container">
<h1>회원 가입 폼입니다.</h1>
<form action="signup.jsp" method="post" onSubmit={handleSubmit}>
<div>
<label htmlFor="id" className="control-label">아이디</label>
{/*
className={`form-control ${valid.isIdValid ? 'is-valid' : 'is-invalid'} `}
className={cn('form-control', {'is-valid':valid.isIdValid, 'is-invalid':!valid.isIdValid && dirty.isIdDirty} }
*/}
<input onChange={onIdChange} type="text" className={cn('form-control', {'is-valid':valid.isIdValid, 'is-invalid':!valid.isIdValid && dirty.isIdDirty} )} name="id" id="id" />
<small className="form-text text-muted">영문자 소문자로 시작하고 5글자~10글자 이내로 입력하세요.</small>
<div className="valid-feedback">사용할 수 있습니다.</div>
<div className="invalid-feedback">사용할 수 없는 아이디입니다.</div>
</div>
<div>
<label htmlFor="pwd" className="control-label">비밀번호</label>
<input onChange={onPwdChange} type="password" className={cn('form-control', {'is-valid':valid.isPwdValid, 'is-invalid':!valid.isPwdValid && dirty.isPwdDirty} )} name="pwd" id="pwd" />
<small className="form-text text-muted">특수 문자를 하나 이상 조합하세요.</small>
<div className="invalid-feedback">비밀번호를 확인하세요.</div>
</div>
<div>
<label htmlFor="pwd2" className="control-label">비밀번호 확인</label>
<input onChange={onPwdChange2} type="password" className={cn('form-control', {'is-valid':valid.isPwdValid, 'is-invalid':!valid.isPwdValid && dirty.isPwdDirty} )} name="pwd2" id="pwd2" />
</div>
<div>
<label htmlFor="email" className="control-label">이메일</label>
<input onChange={onEmailChange} type="text" className={cn('form-control', {'is-valid':valid.isEmailValid, 'is-invalid':!valid.isEmailValid && dirty.isEmailDirty} )} name="email" id="email" />
<div className="invalid-feedback">이메일 형식에 맞게 입력하세요.</div>
</div>
<button className="btn btn-outline-primary" type="submit">회원가입</button>
</form>
</div>
);
}
export default App;
- 두개는 같은 것이다. 함수를 만들어 넣으나 상수를 만들어 넣으나 상관 없음.
- public폴더의 index.html에 bootstrap 추가!
- Tomcat 서버도 켜져 있어야 한다 (아이디 중복검사를 위해, DB에 값을 보내고 응답받아야 하므로)
- checkId 에서 inputId 값을 받아서 json으로 응답하고 있음
- node에서 tomcat으로 값을 보내서 응답받을 것이다.
(원래는 불가능하지만, 어제 cross origin 설정을 해놔서 가능한 것)
- react에서 이 서버로 응답 요청을 보낼것이다.
- find/replace로 편하게 수정하기
- class→className, for→htmlFor
- Whole word(전체 단어) 옵션을 선택하면 오류 없이 수정된다.
- 이전에 Vue를 사용해서 작성한 파일을 보면, data로 10개의 값을 관리하고 있다.
- React에서도 이 10가지를 상태값으로 관리하기!
- object로 관리할 것인지, 하나하나 따로 관리할 것인지 정하면 된다.
- 3개의 object 묶음으로 관리하기로!
- 3개의 object를 관리해준다.
setValid({
...valid, //기존 값을 펼쳐놓고
isIdValid: "T/F" //필요한 값만 수정하는 것으로!!
});
- 위와 같이 object의 기존 내용을 펼쳐놓고 원하는 상태값만 수정하면 된다.
- ID 검증 함수 (onIdChange)
//id가 변경되었을 때 호출하는 함수
const onIdChange=(e)=>{
//현재 입력한 아이디를 읽어와서
let inputId=e.target.value;
//아이디를 한번이라도 입력하면 아이디가 더럽혀 졌는지 여부를 true 로 바꿔준다.
setDirty({
...dirty,
isIdDirty:true
});
//아이디를 검증할 정규표현식
const reg=/^[a-z].{4,9}$/;
//입력한 아이디가 정규표현식과 매칭이 되는지(통과 되는지) 확인한다.
const isMatch=reg.test(inputId);
//만일 매칭되지 않는다면
if(!isMatch){
//아이디 유효성 여부를 false로 바꾼다.
setValid({
...valid,
isIdValid:false
})
return; //함수를 여기서 끝내라
}
//2. 외부 tomcat 서버에 페이지 전환없이 전송을 하고 응답을 받는다.
fetch("http://localhost:8888/Step04_Final/users/checkid.jsp?inputId="+inputId)
.then(function(response){
return response.json();
})
.then(function(data){
//3. 사용가능한지 여부에 따라 아이디 입력란에 is-valid or is-invalid 클래스를 적절히 추가, 제거를 한다.
console.log(data);
if(data.isExist){
setValid({
...valid,
isIdValid:false
});
}else{
setValid({
...valid,
isIdValid:true
});
}
});
}
- 아이디 유효성을 참조하는 방법: valid.isIdValid 하면 된다. 점찍어서 참조하기
- id를 한번이라도 입력한적이 있는지 여부(isIdDirty)도 관리
- input 요소에 입력한 아이디를 기존의 값과 매칭하기
- class를 좀더 편하게 제어하기 위해 classnames를 설치함
- 파일에서도 import하기
className={`form-control ${valid.isIdValid ? 'is-valid' : 'is-invalid'} `}
- id label의 className에 추가될 내용 : id-valid 또는 id-invalid
- 이것이 id 유효성 여부에 따라서 달라진다.
- classNames 모듈을 사용하지 않을 경우 위와 같이 작성
className={`form-control ${valid.isIdValid ? 'is-valid' : 'is-invalid'} `}
className={cn('form-control', {'is-valid':valid.isIdValid, 'is-invalid':!valid.isIdValid} }
- classnames 를 사용하지 않았을 경우 / 사용했을 경우
cn(기본으로 넣을 클래스명 , {T/F 여부에 따라 선택적으로 넣을 클래스명} )
- form-control : 고정으로 항상 넣어놓을 것은 그냥 바로 텍스트 입력
- is-valid / is-invalid : 선택적으로 넣을 방의 이름으로 넣어두고, 값에 boolean 값을 넣어준다.
- True이면 is-valid 가 추가되고, False면 is-invalid가 추가되도록
- 여기에 false조건에는 && dirty.isIdDirty 를 추가해준다.(조건 2가지를 따져서 일치하면 is-invalid를 추가하도록)
- 처음 페이지 로딩시부터 사용할 수 없는 아이디라고 나오지 않고, 한번이라도 입력한 이후에 나오도록!
- pwd 검증 함수 (onPwdChange, onPwdChange2)
//비밀번호를 입력했을 때 실행할 함수 등록
const onPwdChange=(e)=>{
//입력한 비밀번호를 읽어와서
let inputPwd=e.target.value;
//pwd의 상태값에 반영하고
setInput({
...input,
pwd: inputPwd
});
//더렵혀 졌는지 여부를 true로 바꿔준다.
setDirty({
...dirty,
isPwdDirty:true
})
//비밀번호를 검증할 정규 표현식
const reg=/[\W]/;
//만일 정규표현식 검증을 통과하지 못했다면
if(!reg.test(inputPwd)){
setValid({
...valid,
isPwdValid: false
})
return; //함수를 여기서 끝내라
}
//만일 비밀번호 입력란과 확인란이 다르다면
if(inputPwd != input.pwd2){
setValid({
...valid,
isPwdValid:false
})
}else{ //같다면
setValid({
...valid,
isPwdValid:true
})
}
}
const onPwdChange2=(e)=>{
//입력한 비밀번호를 읽어와서
let inputPwd=e.target.value;
//pwd2의 상태값에 반영하고
setInput({
...input,
pwd2: inputPwd
});
setDirty({
...dirty,
isPwdDirty:true
})
//비밀번호를 검증할 정규 표현식
const reg=/[\W]/;
//만일 정규표현식 검증을 통과하지 못했다면
if(!reg.test(inputPwd)){
setValid({
...valid,
isPwdValid: false
})
return; //함수를 여기서 끝내라
}
//만일 비밀번호 입력란과 확인란이 다르다면
if(inputPwd != input.pwd){
setValid({
...valid,
isPwdValid:false
})
}else{ //같다면
setValid({
...valid,
isPwdValid:true
})
}
}
- 이전에 작성한 Vue에서는 각각의 input요소의 모델명이 다르기때문에,
동일한 함수를 호출하더라도 구분해서 각자의 값을 따로 읽어오기가 가능했다.
- 하지만 react에서는 모델을 지정하지 않으므로...
2개의 input요소(pwd, pwd2)에 입력되었을 때의 함수를 각각 다르게 만들어 따로 호출하기로 함!
const onPwdChange=(e)=>{}
const onPwdChange2=(e)=>{}
- onPwdChange
if(input.pwd != input.pwd2){
setValid({
...valid,
isPwdValid:false
})
}else{ //같다면
setValid({
...valid,
isPwdValid:true
})
}
- 주의!! 여기에서 비교대상을 input.pwd 대신 inputPwd 사용
- state를 set으로 반영하는 데에 시간이 좀 걸려서, 이 값을 읽어낼 때 변경된 값이 아직 반영되지 않은 상태일 수 있다.
- 따라서 inputPwd (입력받은 내용) 의 값과 비교하는 것이 좋다.
- Email 검증 함수
//이메일을 입력했을 때 호출되는 함수
const onEmailChange = (e)=>{
let inputEmail=e.target.value;
setDirty({
...dirty,
isEmailDirty:true
})
//이메일을 검증할 정규 표현식
const reg=/^[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*.[a-zA-Z]{2,3}$/i;
//만일 입력된 이메일이 정규표현식 검증을 통과하지 못했다면
if(!reg.test(inputEmail)){
setValid({
...valid,
isEmailValid:false
})
}else{
setValid({
...valid,
isEmailValid:true
})
};
}
- input요소에 입력된 값을 읽어와 검증하는 test() 에 넣어준다.
- !reg.test() 의 T/F여부에 따라 if /else 로 수행할 코드인데,
3항 연산자를 활용해서 좀더 간단하게 작성할 수 있다.
- isEmailValid에 !reg.test() 를 연산한 결과물을 넣어줌
if(!reg.test(inputEmail)){
setValid({
...valid,
isEmailValid:false
})
}else{
setValid({
...valid,
isEmailValid:true
})
};
/* 간략화 */
const isEmailValid = !reg.test(inputEmail) ? false : true;
setValid({...valid, isEmailValid});
- 아래와 같이 작성하면 코드를 좀더 간략화할 수 있다!
- 원래는 setValid({...valid, isEmailValid : isEmailValid}) 라고 써야 하지만,
변수명과 똑같은 이름으로 방도 만들고 값도 들어가게하는 js문법을 사용해서 이렇게 작성한 것!
- 모든 검증식이 완료되었으면 폼을 전송할 함수 handleSubmit 생성
- 폼 전체가 유효하지 않으면 submit을 막아버리도록 한다.
const handleSubmit=(e)=>{
let isFormValid = valid.isIdValid && valid.isPwdValid && valid.isEmailValid;
if(!isFormValid){
e.preventDefault();
}
}
- 3개가 모두 Valid 인 상태이도록 && 으로 조건을 넣어준다.
- 이것은 오리지널 이벤트가 아니고 리액트가 넣어주는 이벤트이다.
(하지만 preventDefault 함수는 똑같으므로 차이 없이 사용해도 무방하다)
- 완성되면 build 해서 이클립스의 users 폴더안에 넣을 예정!
- json 파일안에 homepage 경로 설정!
- npm run build로 만들어진 폴더이다.
- 이 폴더 내용 전체를 복사해서 경로에 붙여넣는다.
- homepage 에서 지정한 위치에 복사한 파일들을 전부 넣어준다.
- 다른 jsp 페이지를 만들어 index.html에 들어있는 한줄짜리 코드를 넣는다.
(위 이미지는 한줄짜리를 보기 편하게 줄바꿈한 것)
- 이 부분이 React에서 만든 앱을 compile한 것이다.
- 홈페이지 설정으로 인해 build 된 파일에 들어가게 된 내용!
- react를 사용해서 브라우저에서 로딩하는 클라이언트 사이드 렌더링으로 만들어진 페이지이지만
jsp로 만들었던 페이지와 똑같이 만들 수 있다.
'국비교육(22-23)' 카테고리의 다른 글
48일차(1)/React(14) : SPA(Single Page Application) 예제(2) (0) | 2022.12.14 |
---|---|
47일차(2)/React(13) : SPA(Single Page Application) 예제 (0) | 2022.12.13 |
46일차(3)/React(11) : React 에서 만든 결과물 배포하기(build) (0) | 2022.12.12 |
46일차(2)/React(10) : import, export 활용 예제(module) (0) | 2022.12.12 |
46일차(1)/React(9) : 함수형 컴포넌트 작성 / ajax 요청으로 DB 데이터 출력 (0) | 2022.12.12 |