1. login
SWR
- 원격상태와 (리액트의) 로컬상태를 하나로 통합해주는 모듈
- 적절한 타이밍에 지속적으로 원격서버에 데이터를 fetch하므로 최신데이터가 갱신됨
- 또한 컴포넌트간 swr의 키값이 같을경우 캐싱된 값을 전달하므로 데이터의 전역적인 공유가 가능해짐
- 프로젝트에서는 로그인 성공시 validate() 함수를 호출하여 swr이 서버에 사용자정보를 로그인 과정에서 인증에 성공한 이메일을 가지고 사용자 정보를 요청하게 된다
- 사용자 정보 요청이 성공하게 될 경우 localStorage 에 성공 이메일을 저장하고 다른 컴포넌트에서 해당 이메일을 가져와
사용자정보를 swr로 요청함 - 이러한 경우 요청한 사용자 정보의 데이터가 일치하면 캐싱된 데이터만 반환하므로 트래픽 과중에 대한 우려가 사라지게 됨
- 사용자 정보 요청이 성공하게 될 경우 localStorage 에 성공 이메일을 저장하고 다른 컴포넌트에서 해당 이메일을 가져와
Login 요청 후 동작 흐름
- 사용자 정보를 서버로부터 얻게될 경우, 기본 창으로 리다이렉트하여 우리 서비스를 인증 및 인가된 사용자로서 제공하면 된다
- 우리 서비스의 프론트에는 채팅기능만 구현되었으므로 /messenger로 리다이렉트 시킨다.
- 또한 로그인이 만약 실패할 경우 useState로 선언된 logInErro값을 true로 바꾸어줌으로써 로그인창 아래에 에러 문구를 띄울 수 있게 한다
const LogIn = () => {
const [email, onChangeEmail] = useInput(' ');
const [password, onChangePassword] = useInput('');
const [logInError, setLogInError] = useState(false);
const {
data: userData,
error,
revalidate,
mutate
} = useSWR<IChatUser | false>(email, fetchByEmail, {
revalidateOnMount: false,
revalidateOnFocus: false,
onSuccess() {
localStorage.setItem("email", email)
}
});
const onSubmit = useCallback(
(e) => {
e.preventDefault();
setLogInError(false);
let bodyFormData = new FormData();
bodyFormData.append("email", email)
bodyFormData.append("password", password)
axios({
method: 'post',
url: '/api/login',
headers: {'Content-Type': 'multipart/form-data'},
data: bodyFormData,
withCredentials: true,
})
.then((response) => {
revalidate()
console.log("login success!")
})
.catch((error) => {
// @ts-ignore
console.log(error.response.status);
setLogInError(error.response.status === 404)
});
},
[email, password],
);
if (userData) {
console.log("redirect to messenger");
return <Redirect to="/messenger"/>;
}
return (
<div id="container">
<Header>HCS</Header>
<Form onSubmit={onSubmit}>
<Label id="email-label">
<span>이메일 주소</span>
<div>
<Input type="email" id="email" name="email"
value={email} onChange={onChangeEmail}/>
</div>
</Label>
<Label id="password-label">
<span>비밀번호</span>
<div>
<Input type="password" id="password" name="password"
value={password} onChange={onChangePassword}/>
</div>
{logInError && <Error>이메일과 비밀번호 조합이 일치하지 않습니다.</Error>}
</Label>
<Button type="submit">로그인</Button>
</Form>
<LinkContainer>
아직 회원이 아니신가요?
<Link to="/signup">회원가입 하러가기</Link>
</LinkContainer>
</div>
);
};
export default LogIn;
2. signup
- email, password 값을 input태그에 작성할 경우 화면에 새로 랜더링이 되어야 하므로 onChangePassword, onChangePasswordCheck 함수를 useCallback 으로 메모이제이션 한다
const SignUp = () => {
const [email, onChangeEmail] = useInput('');
const [nickname, onChangeNickname] = useInput('');
const [password, , setPassword] = useInput('');
const [passwordCheck, , setPasswordCheck] = useInput('');
const [mismatchError, setMismatchError] = useState(false);
const [signUpError, setSignUpError] = useState('');
const [signUpSuccess, setSignUpSuccess] = useState(false);
// 비밀번호를 바꿀 경우
const onChangePassword = useCallback(
(e) => {
setPassword(e.target.value);
setMismatchError(e.target.value !== passwordCheck);
},
[passwordCheck],
);
// 비밀번호 확인을 바꿀 경우
const onChangePasswordCheck = useCallback(
(e) => {
setPasswordCheck(e.target.value);
setMismatchError(e.target.value !== passwordCheck);
},
[password],
)
const onSubmit = useCallback(
(e) => {
e.preventDefault();
if (!mismatchError) {
axios.post('/api/user/', {
email, nickname, password
})
.then((response) => {
console.log(response)
setSignUpSuccess(true);
})
.catch((error) => {
console.log(error.response)
setSignUpError(error.response.data);
})
.finally(() => {
})
}
}, [email, nickname, password, passwordCheck, mismatchError]
)
return (
<div id="container">
<Header>HCS</Header>
<Form onSubmit={onSubmit}>
<Label id="email-label">
<span>이메일 주소</span>
<div>
<Input type="email" id="email" name="email"
value={email} onChange={onChangeEmail}/>
</div>
</Label>
<Label id="nickname-label">
<span>닉네임</span>
<div>
<Input type="text" id="nickname" name="nickname"
value={nickname} onChange={onChangeNickname}/>
</div>
</Label>
<Label id="password-label">
<span>비밀번호</span>
<div>
<Input type="password" id="password" name="password"
value={password} onChange={onChangePassword}/>
</div>
</Label>
<Label id="password-check-label">
<span>비밀번호 확인</span>
<div>
<Input
type="password"
id="password-check"
name="password-check"
value={passwordCheck}
onChange={onChangePasswordCheck}
/>
</div>
{mismatchError && <Error>비밀번호가 일치하지 않습니다.</Error>}
{!nickname && <Error>닉네임을 입력해주세요.</Error>}
{signUpError && <Error>{signUpError}</Error>}
{signUpSuccess && <Success>회원가입되었습니다! 로그인해주세요.</Success>}
</Label>
<Button type="submit">회원가입</Button>
</Form>
<LinkContainer>
이미 회원이신가요?
<Link to="/login">로그인 하러가기</Link>
</LinkContainer>
</div>
);
}
export default SignUp;
출처 :
https://www.inflearn.com/course/%ED%81%B4%EB%A1%A0%EC%BD%94%EB%94%A9-%EC%8B%A4%EC%8B%9C%EA%B0%84%EC%B1%84%ED%8C%85/dashboard
https://github.com/ZeroCho/sleact/tree/master/alecture/pages
'Javascript > React' 카테고리의 다른 글
[React] Spring Boot with React 채팅 서버 : 2-3. utils (0) | 2022.03.10 |
---|---|
[React] Spring Boot with React 채팅 서버 : 2-2. typings (0) | 2022.03.10 |
[React] Spring Boot with React 채팅 서버 : 2-1. hooks (0) | 2022.03.09 |
[React] Spring Boot with React 채팅 서버 : 2. layouts (0) | 2022.03.09 |
[React] Spring Boot with React 채팅 서버 : 1. webpack 설정하기 (0) | 2022.03.09 |