로그인기능 직접 구현
foundation 기간이나 1차프로젝트 기간동안 사실상 로그인, 회원가입 기능은 거의 안해봐서 이번에 해보고 싶었다
1차프로젝트와는 다르게 2차 프로젝트에서는
function형 컴포넌트 및 styled-component를 이용했다!
로그인페이지 전체 레이아웃
// 로그인페이지 전체 레이아웃
<Whole>
<Logo>
<img src="./images/logo.png" alt="제발나와라" />
</Logo>
<LoginContainer>
<Title>로그인</Title>
{LoginDatas.map((LoginData, idx) => {
return <LoginInput key={idx} data={LoginData} />;
})}
<Btn
backColor="red"
textColor="white"
disabled={!check}
onClick={() => handleBtn()} >
로그인
</Btn>
<Help>
<a href="https://www.netflix.com/kr/LoginHelp">
도움이 필요하신가요?
</a>
</Help>
<Footer>
<Btn backColor="transparent" onClick={handleKakao}>
<img src="./images/kakaoBtn.png" alt="kakaoBtn" />
</Btn>
<p>
Flix 회원이 아니신가요?{" "}
<White onClick={() => history.push("/signup")}>
지금 가입하세요
</White>
</p>
<p>이 페이지에 안들어가면 후회하실겁니다!</p>
</Footer>
</LoginContainer>
</Whole>
이렇게 보면 태그들의 형태가 모두 심상치 않은데, 그 이유가 바로 styled-component를 사용했기 때문이다
styled-component 사용하기
- 해당 터미널에서 styled-component 패키지 설치
$ npm install styled-component
- Login.js 상단에서 import하기
import styled from "styled-components";
- 스타일을 지정할 컴포넌트 만들기 (지정하기)
- Lodin 컴포넌트가 모두 렌더된 다음, 하단에 적어주는 것이 구조를 파악하는 데에 있어 도움이 될 것 같다
- 2번에서 import한
styled
+.
+지정하고 싶은 태그이름
~~Whole 컴포넌트는 div태그로 컴포넌트로 만들고 싶어서 아래와 같이[const Whole = styled.div``]
으로 적어주었다 - 지정해주고 싶은 스타일 속성은 백틱 사이에 적어주면 된다
- scss와 달리 css 문법을 유지할 수 있는 장점이 있다
const Whole = styled.div`
display: flex;
justify-content: center;
align-items: center;
width: 100vw;
height: 100vh;
background-image: url("https://images.unsplash.com/photo-1545630478-cf62cdd247d1?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8MjR8fG1vdmllc3xlbnwwfHwwfHw%3D&auto=format&fit=crop&w=800&q=60");
`;
내용 자체는 잘 안보이겠지만
Login 컴포넌트 내부에서 사용하는 styled-component
자체가 적지 않기 때문에
만약 컴포넌트를 위에 선언하다보면 rendering되는 중요한 부분을 확인하기 힘들 것이다
function형 자식컴포넌트에 props 전달하는 방법
// 배열 LoginDatas
const LoginDatas = [
{
name: userEmail,
title: "이메일주소",
type: "email",
validation: emailCheck,
inputAlert: "정확한 이메일 주소으로 입력해주세요.",
setName: setUserEmail
}, {
name: userPw,
title: "비밀번호",
type: "password",
validation: pwCheck,
inputAlert: "8자 이상 영문 대 소문자, 숫자, 특수문자를 사용하세요.",
setName: setUserPw
}
];
// 아이디, 비밀번호 입력하는 Input창
{LoginDatas.map((LoginData, idx) => {
return <LoginInput key={idx} data={LoginData} />;
})}
// 자식 컴포넌트인 LoginInput.js
const { name, title, type, validation,
inputAlert, setName }= props.data;
return (
<InputContainer>
<PlaceHolder>{title}</PlaceHolder>
<Input name={name} type={type}
onChange={e => setName(e.target.value)} />
{validation && <InputAlert>{inputAlert}</InputAlert>}
</InputContainer>
);
배열 LoginDatas에서 map()함수를 이용해서 각각의 LoginInput 컴포넌트 생성
{LoginDatas.map((LoginData, idx) => { return <LoginInput key={idx} data={LoginData} />; })}
- 자식컴포넌트에게 props 전달하는 방법
이전의 class형 컴포넌트에서 자식 컴포넌트에게 props를 전달했을 때
자식컴포넌트에서는 this.props
로 확인했어야 했지만,
이번의 function형 컴포넌트에서 자식 컴포넌트에게 props를 전달했을 때
자식컴포넌트에서는 props.data
로 확인한다
로그인 버튼을 눌렀을 때 서버와 통신하기
const handleBtn = () => {
fetch("http://10.58.7.101:8000/users/sign-in", {
method: "POST",
body: JSON.stringify({
email: userEmail,
password: userPw,
signup_type: "flix"})
})
.then((res) => res.json())
.then((result) => {
if (result.message === "LOGIN_SUCCESS") {
alert(`Flix의 재미를 느껴보세요!`);
localStorage.setItem("token", result.token);
history.push("/");
} else {
alert("이메일 및 비밀번호를 올바르게 기입해주세요.");
}
});
};
<Btn
backColor="red"
textColor="white"
disabled={!check}
onClick={() => handleBtn()}
>
로그인
</Btn>;
로그인버튼이 눌렸을 때 handleBtn 함수가 실행되는데
사실 이렇게 함수 하나만 호출하는 거면 이런식으로 작성하는 게 더 깔끔해 보인다
onClick={handleBtn}
// fetch() 함수
fetch("http://10.58.7.101:8000/users/sign-in", {
method: "POST",
body: JSON.stringify({
email: userEmail,
password: userPw,
signup_type: "flix"})
})
- 첫 번째 인자 : 서버 API의 URL
- 두 번째 인자 : request 보낼 때 같이 줄 내용으로
- POST방식의 method
- email,password, signup_type의 내용이 담긴 body
http request 구조
이 블로그를 참고하면 좋을 것같다
.then((res) => res.json())
.then((result) => {
if (result.message === "LOGIN_SUCCESS") {
alert(`Flix의 재미를 느껴보세요!`);
localStorage.setItem("token", result.token);
history.push("/");
} else {
alert("이메일 및 비밀번호를 올바르게 기입해주세요.");
}
});
- 서버와의 통신을 통해 받은 response를 내가 가공해서 사용하기 위해 json형식으로 변환하고
- 로그인 통신에서 성공하면 status는 200이 되고, response로 주는 result의 message가 "LOGIN_SUCCESS"이 된다
- "Flix의 재미를 느껴보세요!" 라는 alert를 띄우고
- localStorage 라는 저장소에 result의 token키값을 "token" 이라는 키값으로 저장하고
- main 페이지로 이동하려고 하는데, function형 컴포넌트에서는
this.props.history.push()
메서드를 사용할 수 없어서 아래와 같은방법으로 페이지 이동 로직을 구현했다
function형 컴포넌트 조건에 따라 페이지이동
import { useHistory } from "react-router-dom";
const history = useHistory();
history.push("/");
react-router-dom 패키지에서 useHistory() 메서드를 import한 다음
useHistory() 메서드를 history 라고 지정해서
history.push() 메서드를 사용했다
react-router-dom의 Hook 더 알아보기
이 블로그를 참고해보자!
Author And Source
이 문제에 관하여(로그인기능 직접 구현), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@beanlove97/로그인기능-직접-구현저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)