▶ 매번 만드는 것보다 한 번에 정리하는 것이 낫지 않나?
▶ 해결책 : 커스텀 훅
▶ useCallback에 대해 확실히 알고 있나? -> 정리 필요
(참고 : https://www.daleseo.com/react-hooks-use-callback/)
▶ 첫 번째 인자 : 함수
▶ 두 번째 인자 : 배열 내의 값이 변경될 때까지 저장하고 재사용할 수 있게 함
▶ 두 번째 인자로 넘어온 의존 배열이 변경될 때만 첫 번째 넘어온 함수 호출함
const showUseCallback = useCallback(함수, 배열)
▶ 컴포넌트가 다시 렌더링되더라도 예시 함수(여기서는 fetchUser 함수) 참조값 동일하게 유지, useEffect()로 넘어온 함수는 userId값이 변경되지 않는 한 재호출 되지 않음
import React, { useState, useEffect } from "react";
function Profile({ userId }) {
const [user, setUser] = useState(null);
// 수정 전 : userId가 바뀌든 말든 컴포넌트가 렌더링 될 때마다 새로운 참조값 변경됨,
// useEffect 함수 호출 -> user 상태값 바뀜
// -> 다시 렌더링 -> 다시 useEffect 함수 호출
const fetchUser = () =>
fetch(`https://your-api.com/users/${userId}`)
.then((response) => response.json())
.then(({ user }) => user);
// 수정 후 : fetchUser 함수의 참조값 동일하게 유지
// userId값이 변경되지 않는 한 재호출 되지 않음
const fetchUser = useCallback(
() =>
fetch(`https://your-api.com/users/${userId}`)
.then((response) => response.json())
.then(({ user }) => user),
[userId]
);
useEffect(() => {
fetchUser().then((user) => setUser(user));
}, [fetchUser]);
// ...
}
[예시 - 회원가입]
import React, { useCallback, useState } from "react";
const JoinForm = () => {
const dispatch = useDispatch();
const [email, setEmail] = useState("");
const [nickname, setNickname] = useState("");
const [password, setPassword] = useState("");
const onChangeEmail = useCallback((e) => {
setEmail(e.target.value)
})
const onChangeNickname = useCallback((e) => {
setNickname(e.target.value)
})
const onChangePassword = useCallback((e) => {
setPassword(e.target.value)
})
const onSubmitUserForm = useCallback(() => {
console.log(email, password, nickname);
dispatch(
signupRequest({
email,
password,
nickname,
})
);
}, [password, passwordCheck, term]);
return (
<div>
<div>
<div>
<div>
</div>
<h4>
회원가입
</h4>
</div>
<form
className="mt-8 space-y-6"
action="#"
method="POST"
onSubmit={onSubmitUserForm}
>
<input type="hidden" name="remember" defaultValue="true" />
<div className=" rounded-lg shadow-sm">
<div>
<label htmlFor="email-address" className="sr-only">
Email address
</label>
<input
id="email-address"
value={email}
name="email"
type="email"
autoComplete="email"
required
placeholder="Email"
onChange={onChangeEmail}
/>
</div>
<div>
<label htmlFor="nickname" className="sr-only">
nickname
</label>
<input
id="nickname"
value={nickname}
name="nickname"
type="text"
autoComplete="current-nickname"
required
placeholder="Nickname"
onChange={onChangeNickname}
/>
</div>
<div>
<label htmlFor="password" className="sr-only">
Password
</label>
<input
id="password"
value={password}
name="password"
type="password"
autoComplete="current-password"
required
placeholder="Password"
onChange={onChangePassword}
/>
</div>
<div>
<button
type="submit">
Sign up
</button>
</div>
</form>
</div>
</div>
);
};
export default JoinForm;
[중복되는 것]
▶ 로그인이나 input이 필요한 경우들도 중복됨(내 프로젝트에서는 단어 생성, 수정에서도 같이 적용됨)
const [email, setEmail] = useState("");
const onChangeEmail = useCallback((e) => {
setEmail(e.target.value)
})
import { useState, useCallback } from "react";
export default (initValue = null) => {
const [value, setValue] = useState(initValue); //initValue = 초기값
const handler = useCallback((e) => { //onChang~
setValue(e.target.value);
}, []);
return [value, handler]; //useState와 hanlder를 합침
};
[예시 - 회원가입(커스텀 훅 적용)]
import React, { useCallback, useState } from "react";
import useInput from "../hooks/useInput"; //커스텀 훅 불러옴
const JoinForm = () => {
const dispatch = useDispatch();
const [email, onChangeEmail] = useInput("");
const [nickname, onChangeNickname] = useInput("");
const [password, onChangePassword] = useInput("");
const onSubmitUserForm = useCallback(() => {
console.log(email, password, nickname);
dispatch(
signupRequest({
email,
password,
nickname,
})
);
}, [password, passwordCheck, term]);
return (
<div>
<div>
<div>
<div>
</div>
<h4>
회원가입
</h4>
</div>
<form
className="mt-8 space-y-6"
action="#"
method="POST"
onSubmit={onSubmitUserForm}
>
<input type="hidden" name="remember" defaultValue="true" />
<div className=" rounded-lg shadow-sm">
<div>
<label htmlFor="email-address" className="sr-only">
Email address
</label>
<input
id="email-address"
value={email}
name="email"
type="email"
autoComplete="email"
required
placeholder="Email"
onChange={onChangeEmail}
/>
</div>
<div>
<label htmlFor="nickname" className="sr-only">
nickname
</label>
<input
id="nickname"
value={nickname}
name="nickname"
type="text"
autoComplete="current-nickname"
required
placeholder="Nickname"
onChange={onChangeNickname}
/>
</div>
<div>
<label htmlFor="password" className="sr-only">
Password
</label>
<input
id="password"
value={password}
name="password"
type="password"
autoComplete="current-password"
required
placeholder="Password"
onChange={onChangePassword}
/>
</div>
<div>
<button
type="submit">
Sign up
</button>
</div>
</form>
</div>
</div>
);
};
export default JoinForm;