Custom Hook - 항상 prefix인 "use"로 시작 → react가 linting, error checking 자동으로 해줌
//BEFORE(일반 useState) 사용 export default function App() { const initialState = {something} const **[name, setName] = useState(initialState)** return ( <input type="text" value={name} onChange={e => setName(e.target.value} /> ) }
// (커스텀 훅 만들기) export default function **useLocalStorage**(initialState) { const [value, setValue] = useState(initialState) return [value, setValue] }
//AFTER (커스텀 훅 적용) export default function App() { const **[name, setName] = useLocalStorage(initialState)** return ( <input type="text" value={name} onChange={e => setName(e.target.value} /> ) }
//커스텀 훅 function getSavedValue(key,initialValue){ const savedValue = JSON.parse(localStorage.getItem(key)) //반복될 코드 if (savedValue) return savedValue // initialValue 인자가 함수로 들어왔을 경우! ==> 함수 반환하기 if (initialValue instanceOf Function) return initialValue() // 함수 아니면 그냥 initialValue그대로 반환 return initialValue } export default function useLocalStorage(key, initialState) { // const [value, setValue] = useState(initialState) const [value, setValue] = useState(() => { return getSavedValue(key, initialValue) }) //함수도 받을 수 있음 useEffect(() => { localStorage.setItem(key, JSON.stringify(value)) //ls에는 string만 들어가니까 },[value]) return [value, setValue] }
//👉 사용하기 export default function App() { const [name, setName] = useState("name", "") return ( <input type="text" value={name} onChange={e => setName(e.target.value} /> ) }
세번째 예시(useClickOutside) - 1 :useCallback사용 버전
커스텀훅 사용할 컴포넌트
useCallback으로 감쌈 (why? useClickOutside의 dependency에 callback 함수가 있으므로 클릭시마다 이벤트리스너 생성/삭제가 반복됨 ⇒ useCallback으로 감싸서 useCallback의 디펜던시가 바뀔때만 콜백함수 변하도록 함)