이번에는 custom hooks를 공부해보며 리팩토링 한 코드의 의사코드를 적어보려고 한다. 이번에 usememo와 useCallback를 학습하는 파트였다.
리엑트의 작동상 재랜더링이 되는 경우가 많이 있다. 그럴때마다 모든 값을 다시 받아온다면 데이터를 비효율적으로 계속 불러와야하지만 usememo와 useCallback를 사용하면 특정 값 혹은 특정 변수를 기억해두었다가 재랜더링할때 변화가 없다면 불러오지 않고 그 값을 그대로 사용하는것이다.
하지만 단순히 컴포넌트 내에서 함수를 반복해서 생성하지 않기 위해서 useCallback을 사용하는 것은 큰 의미가 없거나 오히려 손해인 경우도 있다. 따라서 자식 컴포넌트의 props로 함수를 전달해 줄 때 useCallback을 사용하기가 좋다.
[App.js / 리펙토링전 코드]
import { useState } from "react";
import useInput from "./util/useInput";
import Input from "./component/Input";
import "./styles.css";
export default function App() {
//input에 들어가는 상태값 및 로직을 custom hook으로 만들어봅니다.
//until 폴더의 useInput.js 파일이 만들어져 있습니다.
const [firstNameValue, setFirstNameValue] = useState("");
const [lastNameValue, setLastNameValue] = useState("");
const [nameArr, setNameArr] = useState([]);
const handleSubmit = (e) => {
e.preventDefault();
setNameArr([...nameArr, `${firstNameValue} ${lastNameValue}`]);
};
return (
<div className="App">
<h1>Name List</h1>
<div className="name-form">
<form onSubmit={handleSubmit}>
<div className="name-input">
<label>성</label>
<input
value={firstNameValue}
onChange={(e) => setFirstNameValue(e.target.value)}
type="text"
/>
</div>
<div className="name-input">
<label>이름</label>
<input
value={lastNameValue}
onChange={(e) => setLastNameValue(e.target.value)}
type="text"
/>
</div>
<button>제출</button>
</form>
</div>
<div className="name-list-wrap">
<div className="name-list">
{nameArr.map((el, idx) => {
return <p key={idx}>{el}</p>;
})}
</div>
</div>
</div>
);
}
[App.js / 리펙토링 후]
import { useState } from "react";
//useInput 불러오기
import useInput from "./util/useInput";
//Input 불러오기
import Input from "./component/Input";
import "./styles.css";
export default function App() {
const [nameArr, setNameArr] = useState([]);
//useInput에서 보내주는 값을 구조분해할당으로 받기
const [firstValue, firstOnchange, firstReset] = useInput("");
const [lastValue, lastOnchange, lastReset] = useInput("");
//handleSubmit클릭했을때 setNameArr에 값을 전달해주기
//Input값을 비워주기 위해서 firstReset(), lastReset() 사용하기
const handleSubmit = (e) => {
e.preventDefault();
setNameArr([...nameArr, `${firstValue} ${lastValue}`]);
firstReset();
lastReset();
};
return (
<div className="App">
<h1>Name List</h1>
<div className="name-form">
<form onSubmit={handleSubmit}>
//만든 Input custom hook 사용해서 porps 전달해주기
<Input label="성" value={firstValue} onChange={firstOnchange} />
<Input label="이름" value={lastValue} onChange={lastOnchange} />
<button>제출</button>
</form>
</div>
<div className="name-list-wrap">
<div className="name-list">
{nameArr.map((el, idx) => {
return <p key={idx}>{el}</p>;
})}
</div>
</div>
</div>
);
}
[useInput.js]
//useCallback 불러오기
import { useCallback, useState } from "react";
function useInput(initialValue) {
//초기값을 initialValue로 설정하기
const [value, setValue] = useState(initialValue);
//onChange useCallback사용하여 주소값을 저장
const onChange = useCallback((e) => {
const { value } = e.target;
setValue(value);
}, []);
//useCallback을 사용하여 [initialValue]의 값을 기억하고 있다가 그 값이 바뀌면 Input칸이 초기화 될 수 있는 코드
const reset = useCallback(() => setValue(initialValue), [initialValue]);
//useInput() 실행했을때 보여질 값을 return 해주기
return [value, onChange, reset];
}
export default useInput;
[Input.js]
function Input({ value, onChange, label }) {
//props로 전달받아온 값을 넣어주기
return (
<div className="name-input">
<label>{label}</label>
<input value={value} onChange={onChange} type="text" />
</div>
);
}
export default Input;