-
Notifications
You must be signed in to change notification settings - Fork 7
[3주차] 고은 미션 제출합니다. #4
base: master
Are you sure you want to change the base?
Changes from 7 commits
0bc3e51
086863f
66f470a
7ed4324
ae509f6
17258a2
6b8ec7d
3b08979
9134d24
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,4 +28,5 @@ yarn-error.log* | |
.env.development.local | ||
.env.test.local | ||
.env.production.local | ||
.env* | ||
.env* | ||
.now |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,4 @@ | ||
# react-vote-11th | ||
|
||
## 실행 방법 | ||
|
||
``` | ||
npm install | ||
npm run dev | ||
``` | ||
|
||
- npm install : 필요한 모든 패키지를 설치합니다. 처음 1번만 실행하면 됩니다. | ||
- npm run dev : react(next) 웹서버를 localhost:3000에서 실행합니다. | ||
vote-form을 구현하는데 시간을 많이 썼던것같습니다 | ||
axios.put에서 url로 각 후보별 id에 해당하는 인자를 어떻게 넘겨줄지가 어려웠고, 투표 버튼을 클릭해서 투표 완료시 화면에 업데이트 하는점도 어려웠습니다 로그인 오류시 폼 초기화하는걸 getElementById로 하느라 input에 props 전달할때 name으로 안하고 id로 해서 [e.target.id]: e.target.value로 했는데 맞는지 모르겠어요.. | ||
useEffect에 대한 이해도 아직 부족하고 axios사용도 많이 미숙한것같습니다ㅠㅠ! |
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" | ||
} | ||
} | ||
} | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,21 @@ | ||
import React from "react"; | ||
import styled from "styled-components"; | ||
import React from 'react'; | ||
import styled from 'styled-components'; | ||
|
||
import LoginForm from "../src/components/login-form"; | ||
import LoginForm from '../src/components/login-form'; | ||
|
||
export default function Home() { | ||
return ( | ||
<Wrapper> | ||
리액트 투-표 | ||
<LoginForm /> | ||
</Wrapper> | ||
); | ||
return ( | ||
<Wrapper> | ||
<Title>리액트 투-표</Title> | ||
<LoginForm /> | ||
</Wrapper> | ||
); | ||
} | ||
|
||
const Title = styled.h1` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. semantic tag 좋습니다 ㅎㅎ |
||
font-size: 40px; | ||
`; | ||
const Wrapper = styled.div` | ||
min-height: 100vh; | ||
padding: 10rem 40rem; | ||
background-color: Azure; | ||
min-height: 100vh; | ||
padding: 10rem 40rem; | ||
background-color: Azure; | ||
`; |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,14 +1,110 @@ | ||||||||||||||||||||||||||||
import React from "react"; | ||||||||||||||||||||||||||||
import styled from "styled-components"; | ||||||||||||||||||||||||||||
import React, { useState } from 'react'; | ||||||||||||||||||||||||||||
import styled from 'styled-components'; | ||||||||||||||||||||||||||||
import axios from 'axios'; | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
import VoteForm from './vote-form'; | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
export default function LoginForm() { | ||||||||||||||||||||||||||||
return <Wrapper>안녕 나는 로그인 폼!</Wrapper>; | ||||||||||||||||||||||||||||
const [logForm, setLogForm] = useState({ email: '', password: '' }); | ||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
loginForm이 더 적절한 네이밍 같아요! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 안녕 |
||||||||||||||||||||||||||||
const [isloged, setloged] = useState(false); | ||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
위와 마찬가지로 네이밍 변경해주세요~ |
||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
const erasePW = () => { | ||||||||||||||||||||||||||||
document.getElementById('password').value = ''; | ||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
const eraseEmail = () => { | ||||||||||||||||||||||||||||
document.getElementById('email').value = ''; | ||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
const handleFormChange = (e) => { | ||||||||||||||||||||||||||||
setLogForm({ ...logForm, [e.target.id]: e.target.value }); | ||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
const handleSubmit = (logForm) => { | ||||||||||||||||||||||||||||
const { email, password } = logForm; | ||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
handleSubmit 함수내에서 loginForm에 바로 접근할 수 있기 때문에 parameter로 넘겨주지 않아도 될 것 같아요! |
||||||||||||||||||||||||||||
if (email === '' || password === '') { | ||||||||||||||||||||||||||||
alert('모든 항목을 입력해주세요!'); | ||||||||||||||||||||||||||||
return false; | ||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||
axios | ||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
위의 if문에 해당된 경우 return문이 실행되며 함수가 종료되기 때문에, 이후 실행되는 line들은 모두 해당 조건에 충족되지 않는다고 봐도 되겠죠? |
||||||||||||||||||||||||||||
.post(process.env.API_HOST + '/auth/signin/', logForm) | ||||||||||||||||||||||||||||
.then(function (response) { | ||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 화살표함수로 바꿔보세요~ |
||||||||||||||||||||||||||||
console.log(response); | ||||||||||||||||||||||||||||
setloged(true); | ||||||||||||||||||||||||||||
alert('로그인 성공!'); | ||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||
.catch(function (error) { | ||||||||||||||||||||||||||||
if (error.response.status === 404) { | ||||||||||||||||||||||||||||
console.log('unauthorized, logging out ...'); | ||||||||||||||||||||||||||||
alert('이메일이 존재하지 않습니다.'); | ||||||||||||||||||||||||||||
eraseEmail(); | ||||||||||||||||||||||||||||
erasePW(); | ||||||||||||||||||||||||||||
} else if (error.response.status === 422) { | ||||||||||||||||||||||||||||
alert('비밀번호가 일치하지 않습니다!'); | ||||||||||||||||||||||||||||
erasePW(); | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 선택과제도 해주셨네요 ㅠㅠ 대단합니다 |
||||||||||||||||||||||||||||
return Promise.reject(error.response); | ||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
return ( | ||||||||||||||||||||||||||||
<div> | ||||||||||||||||||||||||||||
{!isloged && ( | ||||||||||||||||||||||||||||
<Wrapper> | ||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. indentation space가 4칸으로 설정돼있는 것 같아요 |
||||||||||||||||||||||||||||
<Title>로그인</Title> | ||||||||||||||||||||||||||||
<Row> | ||||||||||||||||||||||||||||
<Label>EMAIL</Label> | ||||||||||||||||||||||||||||
<Input type="text" id="email" onChange={handleFormChange}></Input> | ||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. id 사용 좋네요~! name으로도 바꿔보세요!
Suggested change
|
||||||||||||||||||||||||||||
</Row> | ||||||||||||||||||||||||||||
<Row> | ||||||||||||||||||||||||||||
<Label>PASSWORD</Label> | ||||||||||||||||||||||||||||
<Input | ||||||||||||||||||||||||||||
type="password" | ||||||||||||||||||||||||||||
onChange={handleFormChange} | ||||||||||||||||||||||||||||
id="password" | ||||||||||||||||||||||||||||
></Input> | ||||||||||||||||||||||||||||
</Row> | ||||||||||||||||||||||||||||
<Button onClick={() => handleSubmit(logForm)}>로그인</Button> | ||||||||||||||||||||||||||||
</Wrapper> | ||||||||||||||||||||||||||||
)} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
{isloged && <VoteForm />} | ||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
const Title = styled.h1` | ||||||||||||||||||||||||||||
font-size: 3rem; | ||||||||||||||||||||||||||||
margin-bottom: 4rem; | ||||||||||||||||||||||||||||
margin-top: 25px; | ||||||||||||||||||||||||||||
`; | ||||||||||||||||||||||||||||
const Row = styled.div` | ||||||||||||||||||||||||||||
display: flex; | ||||||||||||||||||||||||||||
flex-direction: row; | ||||||||||||||||||||||||||||
margin-bottom: 2rem; | ||||||||||||||||||||||||||||
`; | ||||||||||||||||||||||||||||
const Button = styled.button` | ||||||||||||||||||||||||||||
display: block; | ||||||||||||||||||||||||||||
margin-left: auto; | ||||||||||||||||||||||||||||
font-size: 1.8rem; | ||||||||||||||||||||||||||||
padding: 0.5rem 1rem; | ||||||||||||||||||||||||||||
border-style: none; | ||||||||||||||||||||||||||||
border-radius: 1rem; | ||||||||||||||||||||||||||||
`; | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
const Label = styled.label` | ||||||||||||||||||||||||||||
font-size: 20px; | ||||||||||||||||||||||||||||
margin-right: auto; | ||||||||||||||||||||||||||||
`; | ||||||||||||||||||||||||||||
const Input = styled.input` | ||||||||||||||||||||||||||||
width: 75%; | ||||||||||||||||||||||||||||
padding: 0.5rem 1rem; | ||||||||||||||||||||||||||||
border: 1px solid grey; | ||||||||||||||||||||||||||||
`; | ||||||||||||||||||||||||||||
const Wrapper = styled.div` | ||||||||||||||||||||||||||||
width: 100%; | ||||||||||||||||||||||||||||
min-height: 30rem; | ||||||||||||||||||||||||||||
background-color: white; | ||||||||||||||||||||||||||||
font-size: 18px; | ||||||||||||||||||||||||||||
padding: 3rem 4rem; | ||||||||||||||||||||||||||||
width: 100%; | ||||||||||||||||||||||||||||
min-height: 30rem; | ||||||||||||||||||||||||||||
background-color: white; | ||||||||||||||||||||||||||||
font-size: 18px; | ||||||||||||||||||||||||||||
padding: 3rem 4rem; | ||||||||||||||||||||||||||||
`; |
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,14 +1,121 @@ | ||||||||||||||
import React from "react"; | ||||||||||||||
import styled from "styled-components"; | ||||||||||||||
import React, { useState, useEffect } from 'react'; | ||||||||||||||
import axios from 'axios'; | ||||||||||||||
|
||||||||||||||
export default function VoteForm() { | ||||||||||||||
return <Wrapper>안녕 나는 투표 폼!</Wrapper>; | ||||||||||||||
import styled from 'styled-components'; | ||||||||||||||
|
||||||||||||||
function VoteForm() { | ||||||||||||||
const [candi, setCandi] = useState([]); | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
const [voteCount, setVoteCount] = useState(); | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 state가 사용되지 않고 있어요!, vote시 paramter로 넘겨줄 필요가 없기 때문에 지워주시면 될 것 같아요!
Suggested change
|
||||||||||||||
|
||||||||||||||
useEffect(() => { | ||||||||||||||
getCandidates(); | ||||||||||||||
}, []); | ||||||||||||||
|
||||||||||||||
const getCandidates = async () => { | ||||||||||||||
await axios | ||||||||||||||
.get(process.env.API_HOST + '/candidates/', candi) | ||||||||||||||
.then(({ data }) => { | ||||||||||||||
setCandi(data); | ||||||||||||||
}) | ||||||||||||||
.catch(function (error) { | ||||||||||||||
console.log(error); | ||||||||||||||
}); | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. catch도 화살표함수로 써주세요 😄 |
||||||||||||||
}; | ||||||||||||||
|
||||||||||||||
const voteCandidates = async (person) => { | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. person보다 candidate라는 parameter name이 좋을 것 같아요
Suggested change
|
||||||||||||||
const newUrl = | ||||||||||||||
process.env.API_HOST + '/candidates/' + person._id + '/vote/'; | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 아래처럼 바꿀 수 있습니다!
Suggested change
|
||||||||||||||
await axios | ||||||||||||||
.put(newUrl, voteCount) | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
request body schema가 명시되지 않은 경우, 안 넘겨주셔도 됩니다! |
||||||||||||||
.then(({ data }) => { | ||||||||||||||
setVoteCount(data); | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
삭제해주시면 됩니다 ㅎㅎ |
||||||||||||||
alert(person.name + '님에게 투표 완료!'); | ||||||||||||||
getCandidates(); | ||||||||||||||
}) | ||||||||||||||
.catch(function (error) { | ||||||||||||||
console.log(error); | ||||||||||||||
alert('투표 실패!'); | ||||||||||||||
}); | ||||||||||||||
}; | ||||||||||||||
let i = 1; | ||||||||||||||
return ( | ||||||||||||||
<Wrapper> | ||||||||||||||
<Title> | ||||||||||||||
<RedTitle>프론트엔드 인기쟁이</RedTitle>는 누구? | ||||||||||||||
</Title> | ||||||||||||||
<SubTitle>CEOS 프론트엔드 개발자 인기 순위 및 투표 창입니다.</SubTitle> | ||||||||||||||
<VoteArea> | ||||||||||||||
{candi | ||||||||||||||
.sort((person1, person2) => { | ||||||||||||||
return person2.voteCount - person1.voteCount; | ||||||||||||||
}) | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 아래처럼 바꿀 수 있습니다!
Suggested change
|
||||||||||||||
.map((person) => ( | ||||||||||||||
<Row key={JSON.stringify(person)}> | ||||||||||||||
<Rank>{i++}위:</Rank> | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
<CandiName> | ||||||||||||||
{person.name} | ||||||||||||||
<br />[{person.voteCount}표] | ||||||||||||||
</CandiName> | ||||||||||||||
<Button onClick={() => voteCandidates(person)}>투표</Button> | ||||||||||||||
</Row> | ||||||||||||||
))} | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. candidate 한명 한명에 대한 component를 따로 분리해서 map 해보는건 어떨까요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 엇 이게 map안에서 적용되고 있는거 아닌가요..?? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 앗 넵 다른 파일로 분리해보시면 어떨까해서 드린 말씀이었어요! |
||||||||||||||
</VoteArea> | ||||||||||||||
</Wrapper> | ||||||||||||||
); | ||||||||||||||
} | ||||||||||||||
export default React.memo( | ||||||||||||||
VoteForm, | ||||||||||||||
(prev, next) => prev.voteCount === next.voteCount | ||||||||||||||
); | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. VoteForm component에는 prop이 없죠! React.memo는 prop을 비교해서 리렌더를 결정하기 때문에, prop이 없는 component는 아래처럼 비교함수를 안 써주시면 됩니다.
Suggested change
|
||||||||||||||
const Row = styled.div` | ||||||||||||||
display: flex; | ||||||||||||||
flex-direction: row; | ||||||||||||||
align-items: center; | ||||||||||||||
`; | ||||||||||||||
const Button = styled.button` | ||||||||||||||
background-color: navy; | ||||||||||||||
color: white; | ||||||||||||||
font-size: 1.5rem; | ||||||||||||||
padding: 0.5rem 1rem; | ||||||||||||||
border-style: none; | ||||||||||||||
border-radius: 1rem; | ||||||||||||||
`; | ||||||||||||||
const Rank = styled.strong` | ||||||||||||||
font-size: 1.5rem; | ||||||||||||||
margin: 0rem 4rem 1rem 0rem; | ||||||||||||||
`; | ||||||||||||||
const CandiName = styled.p` | ||||||||||||||
font-size: 1.5rem; | ||||||||||||||
display: block; | ||||||||||||||
margin: 0rem auto 1rem 0rem; | ||||||||||||||
`; | ||||||||||||||
const VoteArea = styled.div` | ||||||||||||||
width: 100%; | ||||||||||||||
padding: 5rem 10rem; | ||||||||||||||
border: 1px solid black; | ||||||||||||||
display: flex; | ||||||||||||||
flex-direction: column; | ||||||||||||||
justify-content: space-between; | ||||||||||||||
`; | ||||||||||||||
const Title = styled.span` | ||||||||||||||
font-size: 3rem; | ||||||||||||||
color: black; | ||||||||||||||
display: inline-block; | ||||||||||||||
font-weight: bold; | ||||||||||||||
`; | ||||||||||||||
const RedTitle = styled.span` | ||||||||||||||
Comment on lines
+64
to
+100
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 용도 별로 다른 태그 사용하신거 너무 잘하셨어요~~ 💯 |
||||||||||||||
font-size: 3rem; | ||||||||||||||
color: crimson; | ||||||||||||||
`; | ||||||||||||||
const SubTitle = styled.h1` | ||||||||||||||
font-size: 2.5rem; | ||||||||||||||
color: grey; | ||||||||||||||
`; | ||||||||||||||
|
||||||||||||||
const Wrapper = styled.div` | ||||||||||||||
width: 100%; | ||||||||||||||
min-height: 30rem; | ||||||||||||||
background-color: white; | ||||||||||||||
font-size: 18px; | ||||||||||||||
padding: 3rem 4rem; | ||||||||||||||
width: 100%; | ||||||||||||||
min-height: 30rem; | ||||||||||||||
background-color: white; | ||||||||||||||
font-size: 18px; | ||||||||||||||
padding: 3rem 4rem 10rem; | ||||||||||||||
`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
굿입니다 👍