Skip to content
This repository has been archived by the owner on Sep 19, 2021. It is now read-only.

[3주차] 유현우 미션 제출합니다. #5

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,5 @@ yarn-error.log*
.env.development.local
.env.test.local
.env.production.local
.env*
.env*
.now
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

## 실행 방법

```
npm install
npm run dev
```
## [3주차] 유현우 미션 제출합니다.

- npm install : 필요한 모든 패키지를 설치합니다. 처음 1번만 실행하면 됩니다.
- npm run dev : react(next) 웹서버를 localhost:3000에서 실행합니다.
이번 미션은 사실 스터디 때 모르는 것들을 다 여쭤보고, 구현을 어느정도 했었기 때문에 그렇게 어렵지는 않았던 것 같습니다! 너무 설명을 잘해주셔가지구 ㅎㅎ 근데 중간 고사 기간이 점점 다가오니 다른 디테일에 신경을 썼어야하는데 신경을 많이 못 쓴 것 같아 아쉽습니다 ㅠㅠ<br>
비동기함수나 Request, Response, axios, POST, GET 같은 개념이나 함수들을 사용하면서 이런 개념들을 더 잘 이해하게 된 것 같습니다. 개념 자체는 알고 있고 한두번씩 써보긴 했었지만 개념이 조금 모호했었는데 이번에 사용하면서 완벽하진 않지만 좀 더 잘 이해하게 된 것 같습니다. <br>
컴포넌트나 state 같은 것들을 사용하면 사용할수록 점점 익숙해지는 것 같습니다. <br>
그런데 아직 memo는 정확히 어떨 때 사용해야하는지 애매하네요..로그인 창에서 쓰는 건 알겠지만 이번에 후보자들 보여주는 창에서는 어디다 넣어야할지 고민하다가 그냥 상위 컴포넌트에 넣었는데 잘 넣었는지 모르겠네요...ㅠㅠ<br>
그리고 예전에 혼자서 과제나 코딩을 할 때는 컨벤션을 엄격하게 지키지 않았는데 계속 보면서 익숙해져야겠습니다...그리고 css 틈 날때마다 공부는 하는데 아직은 생각한대로 척척 짜지지는 않네요..ㅠㅠ<br>
혼자 개발하면 기능 구현은 해도 막개발이라는 생각이 지워지질 않았는데 이렇게 코드 리뷰해주시니까 그런 불안이 많이 없어져서 좋은 것 같습니다. 꼼꼼하게 코드 리뷰해주시느라 항상 감사합니다 ㅎㅎ
12 changes: 12 additions & 0 deletions now.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"version": 2,
"public": false,
"builds": [{ "src": "next.config.js", "use": "@now/next" }],
"build": {
"env": {
"NODE_ENV": "@react-vote-11th-node-env",
"PORT": "@react-vote-11th-port",
"API_HOST": "@react-vote-11th-api-host"
}
}
}
31 changes: 31 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"start": "node server"
},
"dependencies": {
"axios": "^0.19.2",
"compression": "^1.7.4",
"dotenv": "^8.2.0",
"express": "^4.17.1",
Expand Down
16 changes: 13 additions & 3 deletions pages/index.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,29 @@
import React from "react";
import React, { useState } from "react";
import styled from "styled-components";

import LoginForm from "../src/components/login-form";
import VoteForm from "../src/components/vote-form";

export default function Home() {
const [isLoggedIn, setIsLoggedIn] = useState(false);

return (
<Wrapper>
리액트 투-표
<LoginForm />
<Title>리액트 투-표</Title>
{!isLoggedIn && <LoginForm loginSuccess={setIsLoggedIn} />}
{isLoggedIn && <VoteForm />}
</Wrapper>
);
}

const Wrapper = styled.div`
font-size: 3rem;
min-height: 100vh;
padding: 10rem 40rem;
background-color: Azure;
`;

const Title = styled.p`
font-weight: bold;
margin-bottom: 2rem;
`;
32 changes: 32 additions & 0 deletions pages/login.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React, { useState } from "react";
import styled from "styled-components";
import { useRouter } from "next/router";
import LoginForm from "../src/components/login-form";

import Link from "next/link";

export default function Home() {
const router = useRouter();
const { userName } = router.query;
return (
<Wrapper>
<Title>리액트 투-표</Title>
<LoginForm />
<Link href="/vote?userName=최수민">
<a>투표하러가기</a>
</Link>
</Wrapper>
);
}

const Wrapper = styled.div`
font-size: 3rem;
min-height: 100vh;
padding: 10rem 40rem;
background-color: Azure;
`;

const Title = styled.p`
font-weight: bold;
margin-bottom: 2rem;
`;
33 changes: 33 additions & 0 deletions pages/vote.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React, { useState } from "react";
import styled from "styled-components";
import { useRouter } from "next/router";

import VoteForm from "../src/components/vote-form";

export default function Home() {
const router = useRouter();
const { userName } = router.query;
return (
<Wrapper>
<Title onClick={() => router.back()}>리액트 투-표</Title>
<Name>{userName}</Name>님 안녕하세요!
<VoteForm />
</Wrapper>
);
}

const Name = styled.span`
color: blue;
`;

const Wrapper = styled.div`
font-size: 3rem;
min-height: 100vh;
padding: 10rem 40rem;
background-color: Azure;
`;

const Title = styled.p`
font-weight: bold;
margin-bottom: 2rem;
`;
68 changes: 68 additions & 0 deletions src/components/candidate-form.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import React from "react";
import styled from "styled-components";
import axios from "axios";

export default function CandidateForm(props) {
const { name, voteCount, rank, id, refetch } = props;

const voteCandidate = async () => {
await axios
.put(process.env.API_HOST + `/candidates/${id}/vote/`)
.then(function (response) {
console.log(response);
alert(name + "님에게 투표 완료!");
refetch();
// return response.data;
})
.catch(function (error) {
console.log(error);
alert("투표 실패!");
});
};
return (
<Wrapper>
<CandidateRank>{rank}위:</CandidateRank>
<CandidateDesc>
{name}[{voteCount}표]
</CandidateDesc>

<VoteBtn
onClick={() => {
voteCandidate();
}}
>
투표
</VoteBtn>
</Wrapper>
);
}

const Wrapper = styled.div`
display: flex;
justify-content: space-between;
align-items: center;
flex-direction: row;
`;

const CandidateRank = styled.p`
font-weight: bolder;
font-size: 2.5rem;
border: none;
margin: none;
`;
const CandidateDesc = styled.p`
font-size: 2.5rem;
width: 40%;
border: none;
margin: none;
`;
const VoteBtn = styled.button`
background: blue;
color: white;
border: none;
border-radius: 0.7rem;
font-size: 2rem;
height: 3.5rem;
width: 5.5rem;
margin: none;
`;
129 changes: 126 additions & 3 deletions src/components/login-form.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,137 @@
import React from "react";
import React, { useState } from "react";
import axios from "axios";
import styled from "styled-components";

export default function LoginForm() {
return <Wrapper>안녕 나는 로그인 폼!</Wrapper>;
function LoginForm(props) {
//State에 로그인에 필요한 데이터 저장

const [userData, setUserData] = useState({
email: "[email protected]",
password: "example1!",
});

const { loginSuccess } = props;
// 변수 이름 쉽게하기 위해
const { email, password } = userData;

const checkBlank = () => {
// 둘 중 하나라도 안 채워져 있을시 알림
if (email === "" || password === "") {
alert("빈칸 채워주세요!!");
return false;
} else {
return true;
}
};

const initFormData = (status) => {
const initializedUserData = {
email: "",
password: "",
};

switch (status) {
case 404:
alert("이메일이 존재하지 않습니다!!!");
break;
case 422:
alert("비밀번호가 틀렸습니다!!!");
initializedUserData.email = email;
break;
default:
alert("로그인을 다시 시도해주세요!");
}

setUserData(initializedUserData);
};
// 로그인 시도
const tryLogin = () => {
if (checkBlank() === false) {
console.log("실패");
return;
}
axios
.post(process.env.API_HOST + "/auth/signin/", userData)
.then(function (response) {
alert("로그인에 성공하셨습니다!!!");
loginSuccess(true);
console.log(response);
})
.catch(function (error) {
initFormData(error.response.status);
});
};

// 값이 변경될 때
const handleFormChange = (e) => {
const { name, value } = e.target;
setUserData({
...userData,
[name]: value,
});
};

return (
<Wrapper>
<LoginTitle>로그인</LoginTitle>
<InputWrapper>
<InputLabel>EMAIL</InputLabel>
<DataInput name="email" value={email} onChange={handleFormChange} />
</InputWrapper>
<InputWrapper>
<InputLabel>PASSWORD</InputLabel>
<DataInput name="password" type="password" value={password} onChange={handleFormChange} />
</InputWrapper>
<LoginBtn onClick={tryLogin} type="submit">
로그인
</LoginBtn>
</Wrapper>
);
}

export default React.memo(LoginForm);
export const MemoizedLoginForm = React.memo(LoginForm);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

login-form에서는 export 하는 컴포넌트가 하나 뿐이기때문에 default export를 하는 게 좋을 거 같아요. LoginForm의 default export를 React.memo적용한 후에 하는 게 어떨까요?

export default React.memo(LoginForm);


const Wrapper = styled.div`
width: 100%;
min-height: 30rem;
background-color: white;
font-size: 18px;
padding: 3rem 4rem;
`;

const LoginTitle = styled.p`
font-weight: bold;
font-size: 2rem;
margin-bottom: 3rem;
`;

const InputWrapper = styled.div`
width: 100%;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 3rem;
`;

const InputLabel = styled.p`
font-size: 1.5rem;
padding: 0px;
margin: 0px;
`;

const DataInput = styled.input`
border: 1px solid rgb(97, 97, 97);
padding: 0.5rem 0.8rem;
width: 70%;
`;

const LoginBtn = styled.button`
float: right;
background: rgb(222, 222, 222);
font-size: 1.5rem;
padding: 0.5rem 1rem;
border: none;
border-radius: 0.3rem;
`;
Loading