기존의 mock data의 주소를 fetch 함수에 사용하는것이 아니라
직접 벡엔드 서버에서 보내주는 API주소를 사용하여 로그인 구현을 해보았다.
회원가입에 대한 코드를 저장하지 않아서,,,, 우선 벡엔드 데이터 베이스에 등록된
아이디와 비밀번호가 있다고 가정후 코드리뷰를 진행한다.
this.state = {
idValue: '',
pwValue: '',
};
보내주어야 할 아이디와 패스워드를 state로 지정 후
<form onSubmit={this.goToMain}>
<div className="login-input">
<input
name="idValue"
onChange={this.handleInput}
value={this.state.idValue}
type="text"
placeholder="전화번호,사용자 이름 또는 이메일"
/>
<input
name="pwValue"
onChange={this.handleInput}
value={this.state.pwValue}
type="password"
placeholder="비밀번호"
/>
</div>
<button
className="login-button"
disabled={
!(
this.state.idValue.includes('@') &&
this.state.pwValue.length >= 5
)
}
>
<span>로그인</span>
</button>
</form>
JSX언어를 사용하여 렌더안의 return 값으로 다음과 같이 작성하였다.
input 두개를 각각의 함수를 만들어 e.target.value를 저장하였다가 하나의 메소드로 두개의 인풋을 저장하는 방법을 찾아 사용하였다.
바로 계산된 속성명을 사용하는 것!
우선 각각의 input tag에 name속성을 사용하여 이름을 지어주고 (input 태그에는 name 이라는 속성이 있다. 오직 input 태그에만 !)
valuer값을 해당state으로 지정하였다.
handleInput = e => {
const { value, name } = e.target;
this.setState({
[name]: value,
});
};
각각의 input태그의 onClick이벤트의 handleInput 메소드는 호출하게 되는데
setSteat에 대괄호 안에 아까 지정한 name을 넣어주는데 지금 코드는 비구조화 할당을 하여
name과 value만 들어가지만 원래는 e.target.name : e.target.value이다
함수가 실행되면 해당 input의 name과 value값을 인자로 받아 따로 지정하지 않고도 함수를 통일하여 사용이 가능하다.
goToMain = e => {
e.preventDefault();
fetch('http://10.58.4.160:8000/user/signin', {
method: 'POST',
body: JSON.stringify({
account: this.state.idValue,
password: this.state.pwValue,
}),
})
.then(response => response.json())
.then(result => {
if (result.token) {
localStorage.setItem('token', result.token);
}
console.log('결과: ', result);
if (result.message === 'SUCCESS') {
this.props.history.push('/main-myung');
}
});
};
위에 작성한 form태그의 onSubmit이벤트가 감지되면 실행될 함수로는 gotomain이라는 함수이다.
그 함수는 submit의 고유효과인 새로 랜더링되는 상황을 막기위해 e.preventDefault();를 작성해주었다.
fetch함수에는 첫번째 인자로 벡엔드 API 주소를 넣었고, 두번째 옵션객체에는
POST 메소드를 사용하였다.
POST메소드는 body에 보낼 값을 담아 벡엔드에 보내줄 수 있는데 JSON형태로 보내주기위해
JSON.stringify메소드 안에서 값을 지정한다.
벡엔드가 받아올 데이터의 키값을 account와 password를 사용했기 때문에 나도 그에 맞춰서 키값을 지정하고 value에는 사용자 입력값으로 저장된 상태인 state를 각각 넣어주었다.
fetch 함수는 항상 뒤에 promise 함수를 써주어야한다.
그래야 벡엔드와 통신인 잘되었는지 결과를 알 수 있기 때문이다.
첫 번째 then 함수에 전달된 인자 res는 http 통신 요청과 응답에서 응답의 정보를 담고 있는
객체이다.( Response Object!)
하지만 그 객체는 벡엔드에서 넘어오는 응답 body이기 때문에 json 데이터로 사용하기위해서는
Response Object에 json() 호출하여야 한다.
응답 body:
1. 제대로 저장했으면 status code를 200 전달. 응답 body는 없음
2. 권한 오류가 생기면 status code를 403으로 전달하고. 응답 body는 아래와 같음
{
success: false,
message: "권한이 없습니다"
}
.then(res => {
if (res.status === 200) {
alert("저장 완료");
} else if (res.status === 403) {
return res.json();
}
})
.then(res => {
console.log("에러 메시지 ->", res.message);
})
다음과 같이 첫번째 then을 사용하여 통신상태 status를 상황에 따라 결과값을 다르게 할 수 있다.
코드를 풀어보면 200 ok 상태일때 즉, 정상적으로 통신이되면 바로 alert을 실행시키고
아니라면 벡엔드로 부터 받은 응답 body를 json 형태로 변형시킨다.
그리고 두번째 then부터는 console.log가 가능하여 body안의 message에 접근하고
에러메세지 -> 권한이 없습니다. 라는 값을 출력하게된다.
자 이제 본론으로 돌아와서
.then(response => response.json())
.then(result => {
if (result.token) {
localStorage.setItem('token', result.token);
}
console.log('결과: ', result);
if (result.message === 'SUCCESS') {
this.props.history.push('/main-myung');
}
});
나는 로그인 구현 코드에 상태값에 따라 결과를 나누지 않고 console에 출력시켜
console창에서 결과를 확인하였다.
첫번째 then에서는 벡엔드 응답 body를 받아 json형태로 바꿔주었고
두번째 then에서는 token값이 있으면 locolSorage.setItem 메소드를 통해 로컬스토리지에
token이라는 키name 그리고 토큰이 값으로 저장되게 하였다.
그리고 콘솔창에 받아오는 데이터를 출력시켰고
이후 받아온 응답 body객체안의 message키에 접근하여 success를 보내주었다면
this.props.history.push('/main-myung')가 실행되어 메인페이지로 넘어갈 수 있도록 하였다.
이 벨로그를 쓰기전까지는 이렇게 하나하나 이해하면서 사용하지 않았는데
코드리뷰를 통해 각각의 메소드가 어떤 역활을 하며 fetch함수와 promise함수를 어떤 방식으로 사용해야 할지 다른 기능을 구현할 때에도 유용하게 사용할 수 있을것 같다.