React로 nodebirdSNS 만들기 (인프런)/#2 SNS 화면 만들기
#2-4 커스텀 훅 재사용 및 홈 화면 설정,useCallback
정중식
2020. 1. 7. 12:39
쪼개기
- 리액트는 한 페이지에서 모든걸 다 만들면 여러 컴포넌트가 리랜더링 되기때문에 별도의 컴포넌트로 나눠주는게좋다.
(*쪼개면 부모컴포넌트, 자식컴포넌트로 나눠지기때문에 관리에 약간의 어려움이 있는건 사실.*)
- components폴더-> LoginForm.js
import React, { useState, useCallback } from "react";
import Link from "next/link";
import { Form, Input, Button } from "antd";
import { useInput } from "../pages/signup";
// useCallback으로 감싸는 함수기준은 자식 컴포넌트에 넘겨주는 함수는 무조건 감싸준다고 보면됨
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} required />
</div>
<div>
<label htmlFor="user-password">비밀번호</label>
<br />
<Input
name="user-password"
type="password"
value={password}
required
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;
- AppLayout.js
import React, { children } from "react";
import Link from "next/link";
import PropTypes from "prop-types";
import { Menu, Input, Row, Col, Card, Avatar, Form } from "antd";
import LoginForm from "./LoginForm";
// 가짜 데이터
const dummy = {
nickname: "정중식",
Post: [],
Following: [],
Follower: [],
isLoggedIn: false
};
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.Following.length}
</div>,
<div key="follower">
팔로워
<br />
{dummy.Follower.length}
</div>
]}
>
<Card.Meta
avatar={<Avatar>{dummy.nickname[0]}</Avatar>}
title={dummy.nickname}
/>
</Card>
) : (
<LoginForm />
)}
</Col>
<Col xs={24} md={12}>
{children}
</Col>
<Col xs={24} md={6}></Col>
</Row>
</div>
);
};
AppLayout.propTypes = {
children: PropTypes.node
};
export default AppLayout;
커스텀 훅 재사용
- signup.js파일에서 사용한 커스텀 훅을 LoginForm.js 파일에서도 사용해준다
- 커스텀 훅은 리액트에서 form 처리 이벤트 중복을 최소화시켜줘서 좋다.
// 커스텀 훅
export const useInput = (initValue = null) => {
const [value, setter] = useState(initValue);
const handler = useCallback(e => {
setter(e.target.value);
}, []);
return [value, handler];
};
useCallBack()
- useCallback으로 감싸는 함수기준은 자식 컴포넌트에 넘겨주는 함수는 무조건 감싸준다고 보면됨
- jsx에 들어가는 함수인 경우에 useCallback으로 감싸주셔야 합니다. <button onClick={onClick}>처럼 jsx에 들어가는 onClick에요.
- 감싸주지 않으면 onClick 함수가 리렌더링 시마다 새로 만들어집니다. 함수를 새로 만드는 것은 낭비입니다. 새로 만들어지는 것을 막기 위해서 []를 사용하는 거고, 새로 만들어주어야 하는 특별한 경우가 생기는데(useCallback에서 사용하는 state가 바뀐다거나) 그럴 때 새로 만드는 기준이 될 state를 배열 안에 넣어줍니다.
.[] 빈 대괄호는 한번만 리렌더링 된다는뜻이고, 대괄호안에 새로만드는 기준이될 state를 배열안에넣어주면 []안의 내용이 바뀔때마다 리렌더링 , 즉 함수가 새롭게 생성됨