react,next 01. 회원가입 폼 만들기
09 Jul 2020 | react nextreact,next 05. 회원가입 폼 만들기
custom Hook과 useCallBack이 사용되었습니다.
signup.js
회원가입페이지에쓰이는 form과 input 코드 특성상 반복되는 코드가 많다.
reactForm라이브러리를 쓰기도하지만, 여기선 custom Hook으로 반복코드를 최소화시켰고 useCallback을 사용해 리소스를 최소화시켰다.
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 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("");
const onSubmit = useCallback(
(e) => {
e.preventDefault();
if (password !== passwordCheck) {
return setPasswordError(true);
}
if (!term) {
return setTermError(true);
}
},
[password, passwordCheck, term]
);
// 이 함수는 passwordCheck를 칠때마다 발생하는데, password랑 같은지 체크해줌
const onChangePasswordCheck = useCallback(
(e) => {
setPasswordError(e.target.value !== password);
setPasswordCheck(e.target.value);
},
[password]
);
const onChangeTerm = useCallback((e) => {
setTermError(false);
setTerm(e.target.checked);
}, []);
return (
<>
<Form onSubmit={onSubmit} style=>
<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-pass">비밀번호체크</label>
<br />
<Input
name="user-pass-check"
type="password"
value={passwordCheck}
required
onChange={onChangePasswordCheck}
/>
{passwordError && (
<div style=>비밀번호가 일치하지 않습니다.</div>
)}
</div>
<div>
<Checkbox name="user-term" checked={term} onChange={onChangeTerm}>
제로초 말을 잘 들을 것을 동의합니다.
</Checkbox>
{termError && (
<div style=>약관에 동의하셔야 합니다.</div>
)}
</div>
<div style=>
{/* antd에선type="submit"하려면 htmlType을 써줘야함 */}
<Button type="primary" htmlType="submit">
가입하기
</Button>
</div>
</Form>
</>
);
};
export default signup;
커스텀 훅
- 커스텀 hook을 만들면 컴포넌트 로직을 재사용 가능한 함수로 뽑아낼 수 있다.
const useInput = (initValue = null) => {
const [value, setter] = useState(initValue);
const handler = useCallback((e) => {
setter(e.target.value);
}, []);
return [value, handler];
};
커스텀 훅을 사용하기전의 코드
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 [id, setId] = useState("");
const [nick, setNick] = useState("");
const [password, setPassword] = useState("");
const onSubmit = useCallback(
(e) => {
e.preventDefault();
if (password !== passwordCheck) {
return setPasswordError(true);
}
if (!term) {
return setTermError(true);
}
},
[password, passwordCheck, term]
);
const onChangeId = (e) => {
setId(e.target.value);
};
const onChangeNick = (e) => {
setNick(e.target.value);
};
const onChangePassword = (e) => {
setPassword(e.target.value);
};
// 이 함수는 passwordCheck를 칠때마다 발생하는데, password랑 같은지 체크해줌
const onChangePasswordCheck = useCallback(
(e) => {
setPasswordError(e.target.value !== password);
setPasswordCheck(e.target.value);
},
[password]
);
const onChangeTerm = useCallback((e) => {
setTermError(false);
setTerm(e.target.checked);
}, []);
return (
<>
<Head>
<title>NodeBird</title>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/antd/3.23.1/antd.css"
/>
</Head>
<AppLayout>
<Form onSubmit={onSubmit} style=>
<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-pass">비밀번호체크</label>
<br />
<Input
name="user-pass-check"
type="password"
value={passwordCheck}
required
onChange={onChangePasswordCheck}
/>
{passwordError && (
<div style=>비밀번호가 일치하지 않습니다.</div>
)}
</div>
<div>
<Checkbox name="user-term" checked={term} onChange={onChangeTerm}>
제로초 말을 잘 들을 것을 동의합니다.
</Checkbox>
{termError && (
<div style=>약관에 동의하셔야 합니다.</div>
)}
</div>
<div style=>
{/* antd에선type="submit"하려면 htmlType을 써줘야함 */}
<Button type="primary" htmlType="submit">
가입하기
</Button>
</div>
</Form>
</AppLayout>
</>
);
};
export default signup;
커스텀 훅을 사용한후의 코드
훨씬 간결해진 모습
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 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("");
const onSubmit = useCallback(
(e) => {
e.preventDefault();
if (password !== passwordCheck) {
return setPasswordError(true);
}
if (!term) {
return setTermError(true);
}
},
[password, passwordCheck, term]
);
// 이 함수는 passwordCheck를 칠때마다 발생하는데, password랑 같은지 체크해줌
const onChangePasswordCheck = useCallback(
(e) => {
setPasswordError(e.target.value !== password);
setPasswordCheck(e.target.value);
},
[password]
);
const onChangeTerm = useCallback((e) => {
setTermError(false);
setTerm(e.target.checked);
}, []);
return (
<>
<Form onSubmit={onSubmit} style=>
<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-pass">비밀번호체크</label>
<br />
<Input
name="user-pass-check"
type="password"
value={passwordCheck}
required
onChange={onChangePasswordCheck}
/>
{passwordError && (
<div style=>비밀번호가 일치하지 않습니다.</div>
)}
</div>
<div>
<Checkbox name="user-term" checked={term} onChange={onChangeTerm}>
제로초 말을 잘 들을 것을 동의합니다.
</Checkbox>
{termError && (
<div style=>약관에 동의하셔야 합니다.</div>
)}
</div>
<div style=>
{/* antd에선type="submit"하려면 htmlType을 써줘야함 */}
<Button type="primary" htmlType="submit">
가입하기
</Button>
</div>
</Form>
</>
);
};
export default signup;
useCallBack
-
useCallback은 특정 함수를 새로 만들지 않고 재사용하고 싶을때 사용한다.
- 객체는 렌더링되면 완전히 새로운 객체가되어버린다. 새로운 객체가만들어지면 리액트는 렌더링을 시킨다.
- 함수도 객체다.
-
함수 안에서 사용하는 상태 혹은 props 가 있다면 꼭, deps 배열안에 포함시켜야 된다.
코드 사용예시
const onChangePasswordCheck = useCallback(
(e) => {
setPasswordError(e.target.value !== password);
setPasswordCheck(e.target.value);
},
[password]
);
const onChangeTerm = useCallback((e) => {
setTermError(false);
setTerm(e.target.checked);
}, []);