개키우는개발자 : )

React SNS 2-1. _app.js로 레이아웃 분리하기 본문

React/React SNS Project

React SNS 2-1. _app.js로 레이아웃 분리하기

DOGvelopers 2019. 5. 17. 08:35
반응형

중복되는 레이아웃 들을 분리하는 작업.

 

index.js , profile.js signup.js 의 모든 파일에 같은 코드가 중복이 되는 영역이 있다.

<Head>
	<title>NodeBird</title>
	<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/antd/3.18.1/antd.css" />
	<script src="https://cdnjs.cloudflare.com/ajax/libs/antd/3.18.1/antd.js"></script>
</Head>
<AppLayout>
</AppLayout>

Head영역과 AppLayout 영역이 중복이 된다. 그렇기 때문에 저 부분을 분리 해준다.

 

레이아웃을 위한 파일을 Next 가 지정해 놓았다 pages 폴더 안에 _app.js 라고 파일을 생성한다. 모든 js 파일이 _app.js를 부모 컴포넌트로 인식한다.

_app.js 파일 경로

_app.js 작성

import React from 'react';
import Head from 'next/head';
import AppLayout from '../components/AppLayout';

const NodeBird = ({ Component }) => {
    return (
        <>
            <Head>
                <title>NodeBird</title>
                <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/antd/3.18.1/antd.css" />
                <script src="https://cdnjs.cloudflare.com/ajax/libs/antd/3.18.1/antd.js"></script>
            </Head>
            <AppLayout>
                <Component />
            </AppLayout>
        </>
    );
}

export default NodeBird;

Next app.js 는 props로 Component 라고 받는다. Next에서 index,profile,signup을 부모 Component에 자동으로 넣어준다. 

 

index.js 

import React from 'react';

const Home = () =>{
    return (
        <>
            <div>Hello, Next!</div>
        </>
    );
};

export default Home;

profile.js

import React from 'react';

const Profile = () =>{
    return (
        <>
            <div>내 프로필</div>
        </>
    );
};

export default Profile;

signup.js

 

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

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를 사용하지 않기때문에 빈값
    },[]);

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

    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/>
                <Input name="user-id" value={id} required onChange={onChangeId} />
            </div>
            <div>
                <label htmlFor="user-nick">닉네임</label><br/>
                <Input name="user-nick" value={nick} required onChange={onChangeNick} />
            </div>
            <div>
                <label htmlFor="user-password">비밀번호</label><br/>
                <Input name="user-password" type="password" value={password} required onChange={onChangePassword} />
            </div>
            <div>
                <label htmlFor="user-password-check">비밀번호체크</label><br/>
                <Input 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;

최적화

강좌에선 지나친 최적화 이다 라고 말씀하셨다. 하지만 예제 로 보여줬다.

기존의 antd Input 을 memo를 적용해 퓨어 컴포넌트로 적용

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

const TextInput = memo(({value, onChange , name , type}) => {
    return (
        <Input type={type} name={name} value={value} required onChange={onChange} />
    );
});

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를 사용하지 않기때문에 빈값
    },[]);

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

    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;

상단의 TextInput을 만들고 새로 적용한 모습니다.

input을 작성할때 소모적인 리랜더링을 막아주는데 꼼꼼하신분들은 이런 작업을 모두 하시면 성능에 더욱더 최적화가

될겁니다.

반응형
Comments