개키우는개발자 : )

React SNS 2-4. 커스텀 훅 재사용하기 본문

React/React SNS Project

React SNS 2-4. 커스텀 훅 재사용하기

DOGvelopers 2019. 5. 17. 13:31
반응형

로그인 폼 만들기 

 

dummy 데이터의  isLoggedIn : true 이면 로그인 상태 false 이면 로그아웃 상태를 삼항 연산자로 비교를 하였습니다.

import React from 'react';
import Link from 'next/link';
import {Menu, Input , Button, Row , Col , Card , Avatar , Form} from 'antd';
import PropTypes from 'prop-types';

const dummy = {
    nickname : 'Dogveloper',
    Post : [],
    Followings : [],
    Followers : [],
    isLoggedIn : true,
};

const AppLayout = ({children}) =>{
    return (
        <div>
            <Menu mode="horizontal">
                <Menu.Item key="home"><Link href="/"><a>노드버드</a></Link></Menu.Item>
                <Menu.Item key="profile"><Link href="/profile"><a>프로필</a></Link></Menu.Item>
                <Menu.Item key="mail">
                    <Input.Search enterButton style={{verticalAlign:'middle'}} />
                </Menu.Item>
            </Menu>
            <Row>
                <Col xs={24} md={6} >
                    {dummy.isLoggedIn 
                        ?<Card
                            actions={[
                                <div key="twit">짹짹<br/>{dummy.Post.length}</div>,
                                <div key="following">팔로잉<br/>{dummy.Followings.length}</div>,
                                <div key="follower">팔로워<br/>{dummy.Followers.length}</div>,
                            ]}
                        >
                        <Card.Meta 
                            avatar={<Avatar>{dummy.nickname[0]}</Avatar>}
                            title={dummy.nickname}
                        />
                    </Card>
                    :
                    <Form>
                        <div>
                            <label htmlFor="user-id">아이디</label>
                            <br />
                            <Input name="user-id"/> 
                        </div>
                        <div>
                            <label htmlFor="user-id">비밀번호</label>
                            <br />
                            <Input name="user-id" type="password" /> 
                        </div>
                        <div>
                            <Button type="primary" htmlType="submit" loading={false} >로그인</Button>
                            <Link href="/signup"><a><Button>회원가입</Button></a></Link>
                        </div>
                    </Form>
                    }
                </Col>
                <Col xs={24} md={12} >{children}</Col>
                <Col xs={24} md={6} >세번째</Col>
            </Row>
            
        </div>
    );
};

AppLayout.propTypes = {
    children : PropTypes.node,
};

export default AppLayout;

isLoggedIn : true

로그인 상태

isLoggedIn : false 

로그인 전 상태

 

하지만 로그인 폼의 문제점중 하나가 로그인 영역에서 setStatus를 할 때마다 모든 영역이 리 랜더링 되면서 쓸모없는 리소스가 소모됩니다. 그렇기 때문에 loginForm을 따로 컴포넌트 합니다. 

영역을 나눠야 할때 헷갈리는 부분이 많으므로 일단 한 곳에 작성 후 그 이후에 나누어 주면 편하게 나눌 수 있습니다.

 

component 폴더 안에 LoginForm.js 를만듭니다.

LoginForm

LoginForm.js

import React, { useCallback } from 'react';
import { Input , Form , Button } from 'antd';
import Link from 'next/link';
import { useInput } from '../pages/signup';

const LoginForm = () => {
    const [id , onChangeId] = useInput('');
    const [password , onChangePassword] = useInput('');
    const onSubmitForm = useCallback((e) => {
        e.preventDefault();
        console.log({
            id,
            password
        })
    },[id,password]);
    return (
        <Form onSubmit={onSubmitForm}>
            <div>
                <label htmlFor="user-id">아이디</label>
                <br />
                <Input name="user-id" value={id} onChange={onChangeId} /> 
            </div>
            <div>
                <label htmlFor="user-id">비밀번호</label>
                <br />
                <Input name="user-id" type="password"  value={password} onChange={onChangePassword} /> 
            </div>
            <div>
                <Button type="primary" htmlType="submit" loading={false} >로그인</Button>
                <Link href="/signup"><a><Button>회원가입</Button></a></Link>
            </div>
        </Form>
    );
}
export default LoginForm;

이전 포스팅에서 signup.js 에 custom hook을 만들어놓은 게 있다. 그 커스텀 훅을 import 받아와서 로그인 폼에서 사용할 수가 있다.

 

signup.js

import React, {useState, useCallback, memo} from 'react';
import { Form , Input , Checkbox , Button} from 'antd';

//퓨어 컴포넌트가 적용안된 컴포넌트를 강제로 적용시키기 위해 memo를 적용한다.
const TextInput = memo(({value, onChange , name , type}) => {
    return (
        <Input type={type} name={name} value={value} required onChange={onChange} />
    );
});

 //반복되는 코드들을 Coustom Hook을 활용하여 줄여줄 수 있다.
 export const useInput = (initValue = null) =>{
    const [value,setter] = useState(initValue);
    const handler = useCallback((e) => {
        setter(e.target.value);
    },[]);
    return [value,handler];
};

const Signup = () =>{
    const [passwordCheck,setPasswordCheck] = useState('');
    const [term,setTerm] = useState(false);
    const [passwordError,setPasswordError] = useState(false);
    const [termError,setTermError] = useState(false);

    const onSubmit = useCallback((e) => {
        e.preventDefault();
        /**검증 로직 만들기
         * 1. 비밀번호와 비밀번호 체크가 다를 경우를 검증한다
         * 2. 약관 동의를 확인한다.
         */
        if(password !== passwordCheck){
            return setPasswordError(true);
        }
        if(!term){
            return setTermError(true);
        }
        
        //useCallback 하면 state 들을 dependence 배열에 넣어줍니다.
        //그래야 dependence 가 바뀔때 이벤트 함수가 생성이됩니다.
    },[password,passwordCheck,term]);

    const onChangePasswordChk = useCallback((e) => {
        //비밀번호를 입력할때마다 password 를 검증하는 함수
        setPasswordError(e.target.value !== password);
        setPasswordCheck(e.target.value);
        //password state를 사용하기때문에 password를 넣어준다
    },[passwordCheck]);
    const onChangeTerm = useCallback((e) => {
        //체크박스 초기화
        setTermError(false);
        setTerm(e.target.checked);
        //state를 사용하지 않기때문에 빈값
    },[]);

    const [id,onChangeId] = useInput('');
    const [nick,onChangeNick] = useInput('');
    const [password,onChangePassword] = useInput('');

    return (
        <>
        <Form onSubmit={onSubmit} style={{padding:10}}>
            <div>
                <label htmlFor="user-id">아이디</label><br/>
                <TextInput name="userId" type="text" value={id} onChange={onChangeId} />
            </div>
            <div>
                <label htmlFor="user-nick">닉네임</label><br/>
                <TextInput name="user-nick" type="text" value={nick} required onChange={onChangeNick} />
            </div>
            <div>
                <label htmlFor="user-password">비밀번호</label><br/>
                <TextInput name="user-password" type="password" value={password} required onChange={onChangePassword} />
            </div>
            <div>
                <label htmlFor="user-password-check">비밀번호체크</label><br/>
                <TextInput name="user-password-check" type="password" value={passwordCheck} required onChange={onChangePasswordChk} />
                {passwordError && <div style={{color : 'red'}}>비밀번호가 일치하지 않습니다.</div>}
            </div>
            <div>
                <Checkbox name="user-term" value={term} onChange={onChangeTerm}>동의 합니까?</Checkbox>
                {termError && <div style={{color : 'red'}}>약관에 동의하셔야 합니다.</div>}
            </div>
            <div style={{marginTop:10}}>
                <Button type="primary" htmlType="submit" >가입하기</Button>
            </div>
        </Form>
        </>
    );
};

export default Signup;

기존에 const Signup 안에 있던 코드를 밖으로 빼주고 const 앞에 export를 입력한다. 그럼 어디서든 사용할 수 있다.

 

실행

 

로그인 이미지
실행 완료

커스텀 훅이 잘 적용되는 걸 볼 수 있다.

 

출처 : https://www.youtube.com/channel/UCp-vBtwvBmDiGqjvLjChaJw

 

ZeroCho TV

조현영(zerocho)의 JS 프로그래밍 강좌 시간 나는대로 저녁 10시 방송합니다. 컨텐츠: 무료 언어 강좌, 유료 실무 강좌(인프런에 올라감), 오픈소스 기여 방송, 책 쓰는 방송, Vue.js 사이드 프로젝트, 제로초 블로그 업그레이드하기 -- 소개 -- Node.js 교과서...

www.youtube.com

 

반응형
Comments