같다
1. 어제잘못 놓은 store 폴더를 -> front 아래로 이동
_app.js, header, logout, etc 경로 바꾸기
2. hooks 따로 뺴기
front > hooks 생성 > userInput.jsx 생성
import {useState} from 'react'
const useInput =(defaultValue)=>{
const [value,setValue] = useState(defaultValue)
const onChange =e=>{
setValue(e.target.value)
}
//useInput에 들어가 있는 상태 value값 은 value에 onChange함수는 onChange함수에 넣기
return{
value,onChange
}
}
export default useInput
login.jsx
import FormLayout from "../components/FormLayout"
import Head from 'next/head'
import {useState} from 'react'
import Router from 'next/router'
import useInput from '../hooks/useInput'
const Login = () => {
const userid = userInput('') // object
const userpw = userInput('') // object
const handleSubmit=(e)=>{
e.preventDefault()
console.log(userid.value,userpw.value)
userid.value==="asdf" && userpw.value==="asdf" ? Router.push('/') : alert('id 또는 pw가 다릅니다.')
}
return (
<>
<Head>
<title>Blog | 로그인</title>
</Head>
<FormLayout>
로그인 페이지입니다.
<h2>로그인</h2>
<form onSubmit ={handleSubmit}>
{/* html 형태로 보이게끔 한 JavaScript이다! (bable로 가능케함) */}
{/* babel은 type="text" 를 객체로 바꿔줌 type="text" => "type":"text" */}
{/* {} 대괄호를 쓰면 JS 구문을 쓸 수 있게 해주겠다. */}
<input type="text" {...userid} placeholder="아이디를 입력해주세욥" />
<input type="password" {...userpw} placeholder="패스워드를 입력해주세욮" />
<button type="submit">로그인</button>
</form>
</FormLayout>
</>
)
}
export default Login
3. 회원가입
join.jsx
import hooks
import FormLayout from "../components/FormLayout"
import Head from 'next/head'
import useInput from '../hooks/useInput'
const Join = () => {
const username=useInput('')
const userid = useInput('')
const password = useInput('')
const passwordCheck = useInput('')
const userphone = useInput('')
return (
<>
<Head>
<title>Blog | 회원가입</title>
</Head>
<FormLayout>
<h2>회원가입</h2>
<form>
<input type="text" {...username} placeholder="이름을 입력해주세요"/> <br/>
<input type="text" {...userid} placeholder="아이디를 입력해주세요"/> <br/>
<input type="text" {...password} placeholder="비밀번호를 입력해주세요"/> <br/>
<input type="text" {...passwordCheck} placeholder="비밀번호 확인"/> <br/>
<input type="text" {...userphone} placeholder="핸드폰 번호를 입력해주세요"/> <br/>
<button type="submit" >회원가입</button>
</form>
</FormLayout>
</>
)
}
export default Join
password / passwordCheck 은 여기에서만 한번밖에 안쓸꺼라 hooks 안쓸 것 ! (passwordcheck 특히) -> console.log만 찍어보고 삭제 예정
const handleSubmit=(e)=>{
e.preventDefault()
console.log(userid,username,password,passwordCheck,userphone)
}
return (
<>
<Head>
<title>Blog | 회원가입</title>
</Head>
<FormLayout>
<h2>회원가입</h2>
<form onSubmit={handleSubmit}>
-> userid.value 요렇게 다시 바꿔서 console.log
const handleSubmit=(e)=>{
e.preventDefault()
console.log(userid.value,username.value,password.value,passwordCheck.value,userphone.value)
}
* 리액트는 상태를 수시로 체크 가능해서 비밀번호 check 쓰는게 틀리면 바로 메세지 나오도록 만들기
1) -> 먼저 passwordCheck 다 지우기
2) passwordCheck useState ('') 만들기 / setPasswordError (false)
import FormLayout from "../components/FormLayout"
import Head from 'next/head'
import useInput from '../hooks/useInput'
import {useState} from 'react'
const Join = () => {
const username=useInput('')
const userid = useInput('')
const userphone = useInput('')
const password = useInput('')
const [passwordCheck, setPasswordCheck] = useState('')
const [passwordError, setPasswordError] = useState(false)
const handlePassword = e =>{
const {value} = {...e.target}
setPasswordError(password.value!==value) //에러가 나면 true
setPasswordCheck(value)
}
const handleSubmit=(e)=>{
e.preventDefault()
console.log(userid.value,username.value,password.value,userphone.value)
}
return (
<>
<Head>
<title>Blog | 회원가입</title>
</Head>
<FormLayout>
<h2>회원가입</h2>
<form onSubmit={handleSubmit}>
<input type="text" {...username} placeholder="이름을 입력해주세요"/> <br/>
<input type="text" {...userid} placeholder="아이디를 입력해주세요"/> <br/>
<input type="password" {...password} placeholder="비밀번호를 입력해주세요"/> <br/>
<input type="password" value = {passwordCheck} onChange={handlePassword} placeholder="비밀번호 확인"/> <br/>
{passwordError && <div style={{color:'red'}}>비밀번호가 일치하지 않습니다.</div>}
<input type="text" {...userphone} placeholder="핸드폰 번호를 입력해주세요"/> <br/>
<button type="submit" >회원가입</button>
</form>
</FormLayout>
</>
)
}
export default Join
리액트에서 삼항연산자 or 위의 &&으로 한줄 if문을 많이 쓴다고 함 !
{ true && '이거 뜹니다' }
{ false && '이거 안뜹니다' }
4. 약관동의
checkbox 만들어서 상태 만들어주기
import FormLayout from "../components/FormLayout"
import Head from 'next/head'
import useInput from '../hooks/useInput'
import {useState} from 'react'
const Join = () => {
const username=useInput('')
const userid = useInput('')
const userphone = useInput('')
const password = useInput('')
const [passwordCheck, setPasswordCheck] = useState('')
const [passwordError, setPasswordError] = useState(false)
const handlePassword = e =>{
const {value} = {...e.target}
setPasswordError(password.value!==value) //에러가 나면 true
setPasswordCheck(value)
}
const [term,setTerm] = useState(false)
const [termError,setTermError] = useState(false)
const handleTerm = e=>{
setTerm(e.target.checked)
}
const handleSubmit=(e)=>{
e.preventDefault()
console.log(userid.value,username.value,password.value,userphone.value)
}
return (
<>
<Head>
<title>Blog | 회원가입</title>
</Head>
<FormLayout>
<h2>회원가입</h2>
<form onSubmit={handleSubmit}>
<input type="text" {...username} placeholder="이름을 입력해주세요"/> <br/>
<input type="text" {...userid} placeholder="아이디를 입력해주세요"/> <br/>
<input type="password" {...password} placeholder="비밀번호를 입력해주세요"/> <br/>
<input type="password" value = {passwordCheck} onChange={handlePassword} placeholder="비밀번호 확인"/> <br/>
{passwordError && <div style={{color:'red'}}>비밀번호가 일치하지 않습니다.</div>}
<input type="text" {...userphone} placeholder="핸드폰 번호를 입력해주세요"/> <br/>
<input type="checkbox" checked ={term} onChange={handleTerm} /> 약관에 동의해 주십쇼 <br/>
<button type="submit" >회원가입</button>
</form>
</FormLayout>
</>
)
}
export default Join
약관에 동의해주십쇼 글을 클릭해도 체크박스 클릭되게 label 추가
<FormLayout>
<h2>회원가입</h2>
<form onSubmit={handleSubmit}>
<input type="text" {...username} placeholder="이름을 입력해주세요"/> <br/>
<input type="text" {...userid} placeholder="아이디를 입력해주세요"/> <br/>
<input type="password" {...password} placeholder="비밀번호를 입력해주세요"/> <br/>
<input type="password" value = {passwordCheck} onChange={handlePassword} placeholder="비밀번호 확인"/> <br/>
{passwordError && <div style={{color:'red'}}>비밀번호가 일치하지 않습니다.</div>}
<input type="text" {...userphone} placeholder="핸드폰 번호를 입력해주세요"/> <br/>
<input type="checkbox" checked ={term} id="term" onChange={handleTerm} />
<label htmlFor="term">약관에 동의해 주십쇼</label> <br/>
<button type="submit" >회원가입</button>
</form>
</FormLayout>
* 시각장애 or 다른 장애가 있는 분들을 위해 원래 label이 생김 (-> 읽어주는 기능)
이미지의 경우
<img alt="어떤 이미지인지 설명" />
<input title="요것도" />
=> 웹 접근성
TermError
const [term,setTerm] = useState(false)
const [termError,setTermError] = useState(false)
const handleTerm = e=>{
setTermError(e.target.checked !== true) //false -> 문제 없음 // 한 줄 if 문 쓰기 편하도록
setTerm(e.target.checked)
}
.
.
.
<label htmlFor="term">약관에 동의해 주십쇼</label> <br/>
{ termError && <div style={{color:'orange'}}> 약관에 동의해 주십시요22</div>}
<button type="submit" >회원가입</button>
</form>
submit을 했을 떄도 한번 더 체크해주기 (password 첫번째꺼를 지워도 경고문이 안나옴!!!)
const handleSubmit=(e)=>{
e.preventDefault()
if(password.value !==passwordCheck){
setPasswordError(true)
return
}else{
setPasswordError(false)
}
if(!term){ // term이 false면
setTermError(true)
return;
}
console.log(userid.value,username.value,password.value,userphone.value)
}
전체 코드
import FormLayout from "../components/FormLayout"
import Head from 'next/head'
import useInput from '../hooks/useInput'
import {useState} from 'react'
const Join = () => {
const username=useInput('')
const userid = useInput('')
const userphone = useInput('')
const password = useInput('')
const [passwordCheck, setPasswordCheck] = useState('')
const [passwordError, setPasswordError] = useState(false)
const handlePassword = e =>{
const {value} = {...e.target}
setPasswordError(password.value!==value) //에러가 나면 true
setPasswordCheck(value)
}
const [term,setTerm] = useState(false)
const [termError,setTermError] = useState(false)
const handleTerm = e=>{
setTermError(e.target.checked !== true) //false -> 문제 없음 // 한 줄 if 문 쓰기 편하도록
setTerm(e.target.checked)
}
const handleSubmit=(e)=>{
e.preventDefault()
if(password.value !==passwordCheck){
setPasswordError(true)
return
}else{
setPasswordError(false)
}
if(!term){ // term이 false면
setTermError(true)
return;
}
console.log({
username:username.value,
userid:userid.value,
userpw:password.vlaue,
userphone:userphone.value,
})
}
return (
<>
<Head>
<title>Blog | 회원가입</title>
</Head>
<FormLayout>
<h2>회원가입</h2>
<form onSubmit={handleSubmit}>
<input type="text" {...username} placeholder="이름을 입력해주세요"/> <br/>
<input type="text" {...userid} placeholder="아이디를 입력해주세요"/> <br/>
<input type="password" {...password} placeholder="비밀번호를 입력해주세요"/> <br/>
<input type="password" value = {passwordCheck} onChange={handlePassword} placeholder="비밀번호 확인"/> <br/>
{passwordError && <div style={{color:'red'}}>비밀번호가 일치하지 않습니다.</div>}
<input type="text" {...userphone} placeholder="핸드폰 번호를 입력해주세요"/> <br/>
<input type="checkbox" checked ={term} id="term" onChange={handleTerm} />
<label htmlFor="term">약관에 동의해 주십쇼</label> <br/>
{ termError && <div style={{color:'orange'}}> 약관에 동의해 주십시요22</div>}
<button type="submit" >회원가입</button>
</form>
</FormLayout>
</>
)
}
export default Join
5. 대분류 메뉴
카테고리 만들어 뿌리기 (from DB) -> 요걸 json으로 받을 것
NavToggle 파일 정리
components> Accordion.jsx 생성
navtoggle에서 Accordion 관련 코드 빼기
import Styled from 'styled-components'
const Accordion = () => {
return (
<AccordionMenu>
<ul>
<li>대분류 메뉴1</li>
<li>대분류 메뉴2</li>
<li>대분류 메뉴3</li>
<li>대분류 메뉴4</li>
<li>대분류 메뉴5</li>
</ul>
</AccordionMenu>
)
}
export default Accordion
const AccordionMenu = Styled.div`
position:absolute;
width:100%;
left:0px;
top:10vh;
z-index:5;
background: #fff;
padding:7vh 0;
// ()=>{} 근데 {} 요 괄호를 생략해줌
// props 가 가르키는것 : Accodion 이 가진 모든props를 말함
display:${(props)=> (props.flag) ? 'block':'none'};
& > ul{
margin-top:5vh;
display:flex;
flex-direction:column;
}
&>ul>li{
margin-top:20px;
text-align:center;
}
`
NavToggle
import Styled from 'styled-components'
import {useState} from 'react'
import Accordion from './Accodion'
const Toggle = Styled.div`
background:transparent;
border-color:transparent;
& > .nav-toggle {
display:none;
}
& > .nav-toggle + label{
display:block;
width:2.5rem;
height:2rem;
position:relative;
cursor:pointer;
}
& > .nav-toggle + label > span {
display:block;
position:absolute;
width:100%;
height:5px;
border-radius:30px;
background:#000;
transition:all .35s
}
& > .nav-toggle + label > span:nth-child(1){ top: 0 }
& > .nav-toggle + label > span:nth-child(2){
top:50%;
transform:translateY(-50%)
}
& > .nav-toggle + label > span:nth-child(3){ bottom: 0 }
& > .nav-toggle:checked + label > span:nth-child(1){
top:50%;
transform:translateY(-50%) rotate(45deg);
}
& > .nav-toggle:checked + label > span:nth-child(2){
opacity:0;
}
& > .nav-toggle:checked + label > span:nth-child(3){
bottom: 50%;
transform:translateY(50%) rotate(-45deg);
}
`
const NavToggle = () => {
const [visible, setVisible] = useState(false)
const handleToggle = ()=>{
setVisible(!visible)
}
return (
<Toggle>
<input
type="checkbox"
id="nav-toggle"
className="nav-toggle"
onClick={handleToggle}
/>
<label htmlFor="nav-toggle">
<span></span>
<span></span>
<span></span>
</label>
<Accordion visible={visible}/>
</Toggle>
)
}
export default NavToggle
Accordion.jsx
props 받기
const Accordion = ({visible}) => {
return (
대분류 메뉴를 json 형태로 가져오기 (db에서 받았다고 가정)
Accordion.jsx
import Styled from 'styled-components'
const menu = [ // server db 에서 이렇게 데이터가 왔다고 가정
{
id: '1',
category: '대분류메뉴1',
url: '/posts/1'
},
{
id: '2',
category: '대분류메뉴2',
url: '/posts/2'
},
{
id: '3',
category: '대분류메뉴3',
url: '/posts/3'
},
{
id: '4',
category: '대분류메뉴4',
url: '/posts/4'
},
{
id: '5',
category: '대분류메뉴5',
url: '/posts/5'
}
]
const Accordion = ({ visible }) => {
const category = menu.map((v, k)=>{
return <li key={k}>{v.category}</li>
})
return (
<AccordionMenu flag={visible}>
<ul>
{category}
</ul>
</AccordionMenu>
)
}
export default Accordion
Link 연결 url
import Styled from 'styled-components'
import Link from 'next/link'
const Accordion = ({ visible }) => {
const category = menu.map((v, k)=>{
return <li key={v.id}>
<Link href={v.url}>
<a>{v.category}</a>
</Link>
</li>
})
return (
<AccordionMenu flag={visible}>
<ul>
{category}
</ul>
</AccordionMenu>
)
}
=> url은 이동은 하는데 메뉴판이 안닫힘
맨 처음만 (ssr 때문에) 닫힘 근데 두번째부터 page이동이 안됨
페이지 이동 되도록 하기
NavToggle handleToggle 보내기
<span></span>
</label>
<Accordion visible={visible} handleToggle={handleToggle}/>
</Toggle>
)
Accordion.jsx
handleToggle 받고 사용하기
const Accordion = ({ visible, handleToggle }) => {
const handleClick=(e)=>{
handleToggle()
}
const category = menu.map((v, k)=>{
return <li key={v.id} onClick={handleClick}>
<Link href={v.url}>
<a>{v.category}</a>
</Link>
</li>
})
또는 props 받은거 바로 사용하기
const Accordion = ({ visible, handleToggle }) => {
// const handleClick=(e)=>{
// handleToggle()
// }
const category = menu.map((v, k)=>{
return <li key={v.id} onClick={handleToggle}>
<Link href={v.url}>
<a>{v.category}</a>
글쓰기 페이지 꾸미기 --> List page로 수정
posts> [post].jsx
import { useRouter } from 'next/router'
import BlogLayout from "../../components/blogLayout"
import Head from 'next/head'
const data=[ // 응답 받는 임시 data 추가
{
id:'1',
subject:'my blog',
content:"html을 왼쪽 위에서부터 내려옵니다",
date:"2021-07-28",
hit:'10',
},
{
id:'2',
subject:'my blog',
content:"html을 block과 inline 스타일로 나눠집니다",
date:"2021-07-30",
hit:'3',
}
]
const Post = () => {
const router = useRouter()
const { post } = router.query //카테고리 번호(이름) (db에 있는 id값)
//요 id가지고 server에 요청 -> id의 게시물 가져올 수 있도록
const list = data.map((v)=>{
return (
<div key = {v.id}>
<ul>
<li>{v.subject}</li>
<li>{v.content}</li>
<li>{v.date}</li>
</ul>
</div>
)
})
return (
<>
<Head>
<title>Blog | 리스트</title>
</Head>
<BlogLayout>
{post} 리스트
<div>
{list}
</div>
</BlogLayout>
</>
)
}
export default Post
Redux 데이터 중앙관리
리덕스 설치
npm i next-redux-wrapper
npm i redux
npm i react-redux
npm i redux-devtools-extension
Redux devTools 확장 프로그램 설치
'블록체인 기반 핀테크 및 응용 SW개발자 양성과정 일기' 카테고리의 다른 글
[98일차] 20210729 Redux 리덕스 사용법 / reducer 파일 쪼개기 / combine (0) | 2021.07.30 |
---|---|
[95-97일차 복습] 리액트 (+NEXT) 웹 홈페이지 만들기 기초 (레이아웃 / 로그인 / 회원가입) (0) | 2021.07.29 |
[96일차] 20210727 React 리액트, 레이아웃 CSS, 새로고침할 때 CSS 풀리는 현상, (0) | 2021.07.27 |
[95일차]20210726 react Link, head, title, css, 라우터, 폰트, 이미지 넣기, 핸드폰과 연동하기 (0) | 2021.07.26 |
[94일차]20210723 front server 연결 / Next 설치 (0) | 2021.07.23 |