본문 바로가기

블록체인 기반 핀테크 및 응용 SW개발자 양성과정 일기

[97일차]20210728 React 리액트 회원가입 로그인 / 리덕스 설치

반응형

같다

 

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 확장 프로그램 설치 

 

 

 

반응형