node가 실행되면서 (react, express 등이 실행될때) 사용하는 환경 변수를 설정해주는 파일
.env 가장 최상위,(우선순위가 낮다) .env.localhost .env보다 우선순위가 놓은 파일로서 test 환경 제외하고 모든 환경에서 로딩됨 .env.development 개발환경에서만 로딩되는 환경변수들 .env.test 테스트 환경에서만 로딩되는 환경변수들 ...
리액트랑 mysql이랑 연결을 하려면, mysql 정보를 써줘야하는데, 정보를 그대로 올리면 정보가 모든사람이 볼수있겠지❓🤨 그래서 환경 변수에 쓰고 .gitignore에 넣어줘야해 ❗️
.gitignore
.env.local
env.local
DB_HOST=localhost DB_USER=board23user DB_PASSWORD=1234 DA_PORT=3306 DB_DATABASE=board23
app.js
//mysql설정 const pool = mysql.createPool({ host: process.env.DB_HOST, user: process.env.DB_USER, database: process.env.DB_DATABASE, password: process.env.DB_PASSWORD, port: process.env.DB_PORT, });
.env 파일
에 있는 환경변수를 실행중인 프로그램의 env객체 안에 넣는 방법dotenv 라이브러리
를 활용한다.
dotenv.config()
함수를 사용하면 기본적으로.env
안에 있는 변수들을process.env
안에 만들어준다.
이때 만들고 싶은 변수가
.env.local
안에있는 변수라면dotenv.config({path:'경로'})
옵션을 추가하여 만들수있다.
npm i dotenv
app.js
const dotenv = require('dotenv')
dotenv.config({path: '../.env.local'});
📝 src폴더
에 pages폴더
만들어서 auth폴더
를 만들고, 그안에login.js
,
singup.js
파일을 만든다.
📌 login page
랑 signup page
는 스타일이 똑같다.
이렇게 똑같을때는 굳이 둘다 만들필요가 없다.
src폴더
에 styles폴더
만들어서 auth폴더
를 만들고, 그안에auth.styles.js
파일을 만든다.
auth.styles.js
import styled from "@emotion/styled";
export const BgImg = styled.div`
/* border: 5px solid black; */
width: 100%;
background-image: url('/auth-bg.jpg');
background-repeat: no-repeat;
background-size: cover;
background-position: center;
`
export const Wrap = styled.div`
/* border: 5px solid green; */
min-height: 100vh;
/* background-color: black; */
background-color: hsla(var(--ui-color-background-100), 0.8);
display: flex;
justify-content: center;
align-items: center;
position: relative;
padding-top: 100px;
padding-bottom: 150px;
`
export const AuthBox = styled.div`
/* border: 5px solid black; */
width: 400px;
display: flex;
flex-direction: column;
row-gap: 30px;
& > h1{
text-align: center;
}
`
export const AuthForm = styled.form`
/* border: 3px solid gold; */
display: flex;
flex-direction: column;
row-gap: 60px;
`
export const Input = styled.input`
background:none;
padding: 10px 5px;
border-radius: 10px;
border: 1px solid hsl(var(--ui-color-foreground-090));
outline: none;
width: 100%;
`
export const Button = styled.button`
padding: 10px 5px;
border-radius: 10px;
cursor: pointer;
border: none;
background-color: hsl(var(--ui-color-primary));
`
export const ErrMsg = styled.p`
color: red;
font-size: var(--font-xs);
padding-left: 10px;
`
export const InputBoxWrap = styled.div`
display: flex;
flex-direction: column;
row-gap: 20px;
`
export const LogoImg = styled.img`
width: 100px;
align-self: center;
`
export const AuthBody = styled.div`
display: flex;
flex-direction: column;
row-gap: 20px;
`
export const Line = styled.div`
border-top: 1px solid black;
border-left: 1px solid black;
`
export const AuthFooter = styled.div`
display: flex;
justify-content: center;
column-gap: 15px;
align-items: center;
& > .line{
height: 10px;
}
`
export const CancelIcon = styled.div`
position: absolute;
right: 30px;
top: 30px;
cursor: pointer;
`
export const Select = styled.select`
width: 100%;
padding: 10px 15px;
background:none;
& + input{
margin-top: 5px;
border-radius: 1px;
}
`
export const Option = styled.option`
background: rgba(256, 256, 256, 0.8);
padding: 10px;
`
만든것을 모두 다른파일에서도 사용할수있도록 export
해준다
📝 components 폴더
를 만들어준다
signup.js
import { AuthBody, AuthBox, AuthForm, BgImg, Button, CancelIcon, ErrMsg, Input, InputBoxWrap, Option, Select, Wrap } from "../../styles/auth/auth.styles";
import CloseIcon from '@mui/icons-material/Close';
import { useState } from "react";
const JoinPage = () => {
// state 변수 9 개
// 사용자가 email 에 입력한 값
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [passwordCheck, setPasswordCheck] = useState('');
const [question, setQuestion] = useState('');
const [answer, setAnswer] = useState('');
const [emailErrMsg, setEmailErrMsg] = useState('');
const [passwordErrMsg, setPasswordErrMsg] = useState('');
const [passwordCheckErrMsg, setPasswordCheckErrMsg] = useState('');
const [answerErrMsg, setAnswerErrMsg] = useState('');
const emailInputHandler = (e) => {
setEmail(e.target.value);
const emailText = e.target.value;
if (emailText === '') {
setEmailErrMsg('이메일은 필수 입력해주세요');
} else if (!emailText.includes('@')) {
setEmailErrMsg('이메일 형식이 올바르지 않습니다.');
} else {
setEmailErrMsg('');
}
}
const passwordInputHandler = (e) => {
const passwordText = e.target.value;
setPassword(passwordText);
if (passwordText === '') {
setPasswordErrMsg('비밀번호는 필수 입력입니다.');
} else if (passwordText.length < 6) {
setPasswordErrMsg('비밀번호는 6자리 이상이어야 합니다.');
} else {
setPasswordErrMsg('');
}
if (passwordText !== passwordCheck) {
setPasswordCheckErrMsg('비밀번호가 일치하지 않습니다.');
}
}
const passwordCheckInputHandler = (e) => {
const passwordCheckText = e.target.value;
setPasswordCheck(passwordCheckText);
if (passwordCheckText === '') {
setPasswordCheckErrMsg('비밀번호 확인은 필수 입력입니다.');
} else if (passwordCheckText !== password) {
setPasswordCheckErrMsg('비밀번호가 일치하지 않습니다.');
} else {
setPasswordCheckErrMsg('');
}
}
const onSelectHandler = (e) => {
// console.log([e.target]);
setQuestion(parseInt(e.target.value));
}
const onAnswerInputHandler = (e) => {
setAnswer(e.target.value);
if (e.target.value === '') {
setAnswerErrMsg('이메일 찾기 응답은 필수 입력 값입니다.');
} else {
setAnswerErrMsg('');
}
}
return (
<BgImg>
<Wrap>
<CancelIcon><CloseIcon /></CancelIcon>
<AuthBox>
<h1>회원가입</h1>
<AuthBody>
<AuthForm>
<InputBoxWrap>
<div className="input-box">
<Input onChange={emailInputHandler}
type="text" placeholder="아이디" />
<ErrMsg>{
emailErrMsg
}</ErrMsg>
</div>
<div className="input-box">
<Input onChange={passwordInputHandler}
type="password" placeholder="비밀번호" />
<ErrMsg>
{
passwordErrMsg
}
</ErrMsg>
</div>
<div className="input-box">
<Input onChange={passwordCheckInputHandler}
type="password" placeholder="비밀번호 확인" />
<ErrMsg>{
passwordCheckErrMsg
}</ErrMsg>
</div>
<div className="input-box">
<Select onChange={onSelectHandler}>
<Option value={1}>내가 태어난 곳은?</Option>
<Option value={2}>어린시절 나의 별명은?</Option>
<Option value={3}>나의 강아지 이름은?</Option>
</Select>
<Input onChange={onAnswerInputHandler}
type="text" placeholder="이메일을 찾을 때의 질문에 답하세요" />
</div>
</InputBoxWrap>
<Button>회원가입하기</Button>
</AuthForm>
</AuthBody>
</AuthBox>
</Wrap>
</BgImg>
);
}
export default JoinPage;
login.js
import { Link } from "react-router-dom";
import { AuthBody, AuthBox, AuthFooter, AuthForm, BgImg, Button, CancelIcon, ErrMsg, Input, InputBoxWrap, Line, LogoImg, Wrap } from "../../styles/auth/auth.styles";
import CloseIcon from '@mui/icons-material/Close';
const LoginPage = () => {
return (
<BgImg>
<Wrap>
<CancelIcon><CloseIcon /></CancelIcon>
<AuthBox>
<LogoImg src="/logo.svg" alt="logo" />
<AuthBody>
<AuthForm>
<InputBoxWrap>
<div className="input-box">
<Input type="text" placeholder="아이디" />
<ErrMsg>이메일은 필수 입력입니다.</ErrMsg>
</div>
<div className="input-box">
<Input type="password" placeholder="비밀번호" />
<ErrMsg >비밀번호는 필수 입력입니다.</ErrMsg>
</div>
</InputBoxWrap>
<Button>로그인 하기</Button>
</AuthForm>
<Line className="line"></Line>
<AuthFooter>
<Link to="">이메일 찾기</Link>
<Line className="line"></Line>
<Link to="">비밀번호 찾기</Link>
<Line className="line"></Line>
<Link to="/join">회원가입 하기</Link>
</AuthFooter>
</AuthBody>
</AuthBox>
</Wrap>
</BgImg>
);
}
export default LoginPage;
📝 form tag
안에 있는 버튼을 클릭하면 화면이 refresh되는것이 기본동작원리이다. 속에있는값이 전달이 되고, 다시 새로고침이 된다. e.preventDefault();
를 쓰면 클릭해도 새로고침이 안된다.
input 태그
의 값이 변화할때마다state변수
에 저장해준다- 버튼을 클릭 했을떄
state변수
에 저장된 값을 유효한 값인지 검사한다.
그리고, 유효한 값이 아니라면에러메세지 state변수
를 변화해준다.
에러메세지state변수
가 바뀌었으니까,re-rendering
이 된다(에러메세지가 보인다)
모든 input state 변수
의 값이 유효한 값임을 확인했다면값을 서버쪽
으로 전송한다.
📝 state변수는 몇개 만들어야할까❓
정답은❓ 8개
그래서, 여기서 ❗️
formik
yup
라이브러리를 사용한다.
👉 일단은 라이브러리는 없이 사용해보자 ❗️❗️
유효성 검사
validate.js
import React, { useState } from 'react';
const ValidateTest = () => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [emailErrMsg, setEmailErrMsg] = useState('');
const [passwordErrMsg, setPasswordErrMsg] = useState('');
const onJoin = (e) => {
e.preventDefault();//클릭해도 리프레시 안되게함
console.log('email', email);
console.log('password', password);
if (email === '') {
setEmailErrMsg('이메일을 입력해주세요');
} else if (!email.includes('@')) {
setEmailErrMsg('이메일 형식이 올바르지 않습니다.');
} else {
setEmailErrMsg('');
}
if (password === '') {
setPasswordErrMsg('비밀번호를 입력해주세요');
} else if (password.length < 6) {
setPasswordErrMsg('비밀번호는 6자리 이상이어야 합니다.');
} else {
setPasswordErrMsg('');
}
}
const onEmailChange = (e) => {
console.log('e.target.value', e.target.value);
setEmail(e.target.value); //이메일을 입력하면 setEmail을 통해 state 변수에 저장
}
const onPasswordChange = (e) => {
console.log('e.target.value', e.target.value);
setPassword(e.target.value); //비밀번호를 입력하면 setPassword를 통해 state 변수에 저장
}
return (
<>
<h1>유효성검사</h1>
<form>
<input onChange={onEmailChange} id="email" name="email" type="text" placeholder="아이디를 입력하시오" />
<p>{emailErrMsg}</p>
<input onChange={onPasswordChange} id="password" name="password" type="password" placeholder="비밀번호를 입력하시오" />
<p>{passwordErrMsg}</p>
<button onClick={onJoin}>회원가입하기</button>
</form>
</>
);
}
export default ValidateTest;
나중에 한번에 바꿔준다
const [number, setNumber] = useState(0);
function a(){
setNum(100);
setNum(200);
setNum(300);
}
<button onClick={onClick}>버튼</button>
버튼을 클릭하면
number라는 state변수의 값을 100으로 대입되야해
number라는 state변수의 값을 200으로 대입되야해
number라는 state변수의 값을 300으로 대입되야해
마지막 300으로 대입된 값만 화면에 보여진다.
setState 함수에 인자로 함수를 전달한다