상태 관리나 생명주기 메서드를 사용하기 위해서는 클래스 컴포넌트 안에 많은 코드를 작성해야 했기 때문에, 컴포넌트의 가독성이 떨어지고 유지보수하기 어려움
클래스 컴포넌트에서는 this 키워드를 사용해야 하기 때문에, 코드 작성 시 바인딩 문제로 혼란스러움
클래스형 컴포넌트의 이러한 문제점으로 리액트 16.8 버전에서 hook이 추가됨
순수 함수와 데이터 스트림을 사용하여 시간에 따른 시스템 동작을 설명하는 데 중점을 두는 프로그래밍 패러다임
사용자 입력과 같이 데이터가 생성되는 대로 처리하고 시스템 전체에 변경 사항을 자동으로 전파하는 반응형 프로그래밍을 강조
FRP에서는 일반적으로 시간이 지남에 따라 새로운 값을 방출하는 데이터 스트림인 옵저버와 이러한 데이터 스트림의 변경에 반응하는 옵저버로 작업
const useInput = (initialValue, validator) => {
const [value, setValue] = useState(initialValue);
const onChange = e => {
const { target: { value }
} = e;
let willUpdate = true;
if (typeof validator === "function") {
willUpdate = validator(value);
}
if (willUpdate) {
setValue(value);
}
};
return { value, onChange };
};
const useTabs = (initialTab, allTabs) => {
if (!allTabs || Array.isArray(allTabs)) {
return;
}
const [currentIndex, setCurrentIndex = useState(initailTab);
return {
currentItem: allTabs[currentIndex],
changeItem: setCurrentIndex
};
};
const useTitle = initialTitle => {
const [title, setTitle] = useState(initialTitle);
const updateTitle = () => {
const htmlTitle = document.querySelector('title');
htmlTitle.innerText = title;
};
useEffect(updateTitle, [title]);
return setTitle;
};
const useClick = (onClick) => {
if (typeof onClick !== "function"){
return;
}
const element = useRef();
useEffect(() => {
if (element.current) {
element.current.addEventListener("click", onClick);
}
return () => {
if (element.current) {
element.current.removeEventListener("click", onClick);
}
};
}, []);
return element;
};
const useConfirm = (message, callback, rejected) => {
if (typeof callback !== "function" || typeof rejected !== "function") {
return;
}
const confirmAction = () => {
if (confirm(message)) {
callback();
} else {
rejected();
}
};
return confirmAction;
};
const usePreventLeave = () => {
const listner = (event) => {
event.preventDefault();
event.returnValue = "";
};
const enablePrevent = () => {
console.log("enablePrevent");
window.addEventListener("beforeunload", listner);
};
const disablePrevent = () =>
window.removeEventListener("beforeunload", listner);
return { enablePrevent, disablePrevent };
};
const useBeforeLeave = (onBefore) => {
const handle = (event) => {
const { clientY } = event;
console.log(clientY);
if (clientY < 0) onBefore();
};
useEffect(() => {
document.addEventListener("mouseleave", handle);
}, []);
};
const useFadeIn = (duration = 1, delay = 0) => {
if (typeof duration !== "number" || typeof delay !== "number") {
return;
}
const element = useRef();
useEffect(() => {
if (element.current) {
const { current } = element;
current.style.transition = `opacity ${duration}s ease-in-out ${delay}s`;
current.style.opacity = 1;
}
}, []);
return { ref: element, style: { opacity: 0 } };
};
const useNetwork = () => {
const [status, setStatus] = useState(navigator.onLine);
const handleChange = () => {
console.log("handle chage");
setStatus(navigator.onLine);
};
console.log("useNetwork", navigator.onLine);
useEffect(() => {
window.addEventListener("online", handleChange);
console.log("online");
return () => window.removeEventListener("online", handleChange);
}, []);
return status;
};
const useScroll = () => {
const [state, setState] = useState({ x: 0, y: 0 });
const onScroll = (event) => {
setState({ y: window.scrollY, x: window.scrollX });
};
useEffect(() => {
window.addEventListener("scroll", onScroll);
return () => {
window.removeEventListener("scroll", onScroll);
};
}, []);
return state;
};
const useFullScreen = () => {
const element = useRef();
const triggerFul = () => {
if (element.current) {
console.log(element);
element.current.webkitRequestFullscreen();
}
};
return { element, triggerFul };
};
const useNotification = (title, options) => {
if (!("Notification" in window)) {
return;
}
const fireNoti = () => {
if (Notification.permission !== "granted") {
Notification.requestPermission().then((permission) => {
if (permission === "granted") {
new Notification(title, options);
} else {
return;
}
});
} else {
console.log("aaa");
new Notification(title, options);
}
};
return fireNoti;
};
const useAxios = (opts, axiosInsntance = defaultAxios) => {
const [state, setState] = useState({
loading: true,
error: null,
data: null
});
const [trigger, setTrigger] = useState(0);
if (!opts.url) {
return;
}
const refetch = () => {
setState({
...state,
loading: true
});
setTrigger(Date.now());
console.log("refetch", Date.now());
};
useEffect(
() => async () => {
await axiosInsntance(opts)
.then((response) => {
setState({
loading: false,
error: null,
data: JSON.stringify(response)
});
})
.catch((error) => {
setState({
...state,
error: error
});
});
},
[trigger]
);
return { ...state, refetch };
};
export default useAxios;