자주 사용되는 상태 로직을 별도의 사용자 정의 훅으로 만들어서 사용하면 중복 코드를 제거할 수 있고, 편하게 사용이 가능하다.
기존 훅을 조합해서 사용이 가능하다.
// src/App.js
import Box from "./components/Box";
import Checkbox from "./components/Checkbox";
import useHover from "./hooks/useHover";
import useKeyPress from "./hooks/useKeyPress";
import useToggle from "./hooks/useToggle";
function App() {
const [on, toggle] = useToggle();
const [ref, isHover] = useHover();
const keyPressed = useKeyPress("a");
return (
<div>
<Checkbox checked={on} onChange={toggle} />
{isHover ? "hover" : "mouseout"}
<Box ref={ref} />
{keyPressed && "pressed"}
</div>
);
}
export default App;
// src/components/Checkbox.js
const Checkbox = ({ label = "Label", checked = false, onChange }) => {
return (
<label>
{label}
<input type="checkbox" defaultChecked={checked} onChange={onChange} />
</label>
);
};
export default Checkbox;
// src/hooks/useToggle.js
import { useCallback, useState } from "react";
const useToggle = (initialState = false) => {
const [state, setState] = useState(initialState);
const toggle = useCallback(() => setState((state) => !state), []);
return [state, toggle];
};
export default useToggle;
// src/components/Box.js
import styled from "@emotion/styled";
const Box = styled.div`
width: 100px;
height: 100px;
background-color: blue;
`;
export default Box;
// src/hooks/useHover.js
import { useCallback, useEffect, useRef, useState } from "react";
const useHover = () => {
const [state, setState] = useState(false);
const ref = useRef(null);
const handleMouseOver = useCallback(() => setState(true), []);
const handleMouseOut = useCallback(() => setState(false), []);
useEffect(() => {
const element = ref.current;
if (element) {
element.addEventListener("mouseover", handleMouseOver);
element.addEventListener("mouseout", handleMouseOut);
return () => {
element.removeEventListener("mouseover", handleMouseOver);
element.removeEventListener("mouseout", handleMouseOut);
};
}
}, [ref, handleMouseOver, handleMouseOut]);
return [ref, state];
};
export default useHover;
// src/hooks/useKeyPress.js
import { useCallback, useEffect, useState } from "react";
const useKeyPress = (targetKey) => {
const [keyPressed, setKeyPressed] = useState(false);
const handleKeyDown = useCallback(
({ key }) => {
if (key === targetKey) {
setKeyPressed(true);
}
},
[targetKey]
);
const handleKeyUp = useCallback(
({ key }) => {
if (key === targetKey) {
setKeyPressed(false);
}
},
[targetKey]
);
useEffect(() => {
window.addEventListener("keydown", handleKeyDown);
window.addEventListener("keyup", handleKeyUp);
return () => {
window.removeEventListener("keydown", handleKeyDown);
window.removeEventListener("keyup", handleKeyUp);
};
}, [handleKeyDown, handleKeyUp]);
return keyPressed;
};
export default useKeyPress;