import { useState } from "react";
import "./styles.css";
const useInput = (initialValue, validator) => {
const [value, setValue] = useState(initialValue);
const onChange = (event) => {
let willUpdate = true;
if(typeof(validator) === "function"){
willUpdate = validator(event.target.value);
}
if (willUpdate)
setValue(event.target.value);
};
return { value, onChange };
};
// validator는 유호성 검증, 예를 들어 길이 제한이나 특정 문자 입력 못하게게
export default function App() {
// const maxLen = (value) => value.length <= 10;
const forbiddenChr = (value) => !value.includes('@');
const name = useInput("", forbiddenChr);
return (
<div className="App">
<h1>Hello</h1>
<input placeholder="Name" {...name} />
</div>
);
}
import { useState } from "react";
import "./styles.css";
const content = [
{
tab: "Section 1",
content: "I'm the content of the Section 1"
},
{
tab: "Section 2",
content: "I'm the content of the Section 2"
}
];
const useTabs = (initialTab, allTabs) => {
const [currentIndex, setCurrentIndex] = useState(initialTab);
if (!allTabs || !Array.isArray(allTabs)) {
return;
}
return {
currentItem: allTabs[currentIndex],
changeItem:setCurrentIndex
// 얘는 그냥 함수를 리턴한거, changeItem === setCurrentIndex
// click 하면 setCurrentIndex가 호출되어 currentIndex가 변경됨
// 이 후 currentItem도 갱신
};
};
export default function App() {
const { currentItem, changeItem } = useTabs(0, content);
return (
<div className="App">
<h1>Hello</h1>
{content.map((section, index) => (
<button onClick={()=> changeItem(index)}>{section.tab}</button>
))}
<div>{currentItem.content}</div>
</div>
);
}
import { useEffect, useState } from "react";
import "./styles.css";
const useTitle = (initialTitle) => {
const [title, setTitle] = useState(initialTitle);
const updateTitle = () => {
const htmlTitle = document.querySelector("title")
htmlTitle.innerText = title;
};
useEffect(updateTitle, [title]);
return (
setTitle
);
}
export default function App() {
const titleUpdater = useTitle("Loadiing...");
// setTimeout(() => titleUpdater("Home"), 3000);
// 3초 뒤 title을 Home으로 변경
return (
<div className="App">
<div>Hi</div>
</div>
);
}
export default function App() {
const potato = useRef();
// reference는 기본적으로 component를 선택할 수 있는 방법
// document.getElementByID()와 동일
// setTimeout(()=>console.log(potato.current), 3000);
// <input placeholder="la"></input> 출력, 특정 요소 선택 가능
// setTimeout(() => potato.current.focus(), 3000);
// 3초 뒤 input창 focus
return (
<div className="App">
<div>Hi</div>
<input ref={potato} placeholder="la" />
</div>
);
}
import { useEffect, useRef, useState } from "react";
import "./styles.css";
const useClick = (onClick) => {
const element = useRef();
useEffect(() => {
if (element.current) {
element.current.addEventListener("click", onClick);
}
return () => {
if(element.current){
element.current.removeEventListener("click", onClick);
}
}
}, []);
// useEffect에서 반환하는 함수는 cleanup 함수인데, component가 unmount될 때 실행된다.
if (typeof onClick !== "function"){
return;
}
return element;
};
// title은 useClick이 반환한 element라는 ref를 갖는다.
// 해당 ref는 h1 태그에 부여됐고, click 이벤트를 감시하며 click시 인자로 받은 sayHello를 실행행
export default function App() {
const sayHello = () => {
console.log("say Hello");
};
const title = useClick(sayHello);
return (
<div className="App">
<h1 ref={title}>Hi</h1>
</div>
);
}
export const useConfirm = (message, onConfirm, onCancel) => {
if (onConfirm && typeof onConfirm !== "function") {
return;
}
if (onCancel && typeof onCancel !== "function") {
return;
}
// 이걸 계속 작성하는 것이 함수형 프로그래밍을 이해하는데 도움이 됨
const confirmAction = () => {
if (confirm(message)) {
onConfirm();
// confirm은 확인 알림 창 띄우는 함수, ok 누르면 true 리턴턴
} else {
onCancel();
}
// 취소 누르면 onCancel으로 받은 abort가 실행 됨.
};
return confirmAction;
};
import { useEffect, useRef, useState } from "react";
import "./styles.css";
const usePreventLeave = () => {
const listener = (event) => {
event.preventDefault();
event.returnValue = ""; // 이걸 꼭 써줘야 함
};
const enablePrevent = () => window.addEventListener("beforeunload", listener);
const disablePrevent = () =>
window.removeEventListener("beforunload", listener);
// beforeunload -> 사이트를 나갈 때 발생하는 이벤트
return { enablePrevent, disablePrevent };
};
export default function App() {
const { enablePrevent, disablePrevent } = usePreventLeave();
return (
<div className="App">
<h1>Hi</h1>
<button onClick={enablePrevent}>Protect</button>
<button onClick={disablePrevent}>Unprotect</button>
</div>
);
}
import { useEffect, useRef, useState } from "react";
import "./styles.css";
const useBeforeLeave = (onBefore) =>{
if(typeof onBefore !== "function"){
return;
}
const handle = (event) =>{
// console.log(event.clientY);
if(event.clientY <= 0)
onBefore();
};
useEffect(() => {
document.addEventListener("mouseleave", handle);
return ()=> document.removeEventListener("mouseleave", handle);
// 계속해서 event가 쌓이는 것을 막기 위해 cleanup
}, []);
}
export default function App() {
const begForLife = () =>{
console.log("Please dont leave");
}
useBeforeLeave(begForLife);
return (
<div className="App">
<h1>Hi</h1>
</div>
);
}
import { useEffect, useRef, useState } from "react";
import "./styles.css";
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}`;
current.style.opacity = 1;
}
}, []);
return { ref: element, style: { opacity: 0 } };
};
export default function App() {
const fadeInH1 = useFadeIn(1, 2);
const fadeInP = useFadeIn(5, 10);
return (
<div className="App">
<h1 {...fadeInH1}>Hi</h1>
<p {...fadeInP}>hello world</p>
</div>
);
}
import { useEffect, useRef, useState } from "react";
import "./styles.css";
const useNetwork = (onChange) => {
const [status, setStatus] = useState(navigator.onLine);
const handleChange = () => {
if (typeof onChange === "function") {
onChange(navigator.onLine);
}
setStatus(navigator.onLine);
};
useEffect(() => {
window.addEventListener("online", handleChange);
window.addEventListener("offline", handleChange);
return () => {
window.removeEventListener("online", handleChange);
window.removeEventListener("offline", handleChange);
};
}, []);
};
export default function App() {
const online = useNetwork();
return (
<div className="App">
<h1>{online ? "onLine" : "offLine"}</h1>
</div>
);
}
import { useEffect, useRef, useState } from "react";
import "./styles.css";
export default function App() {
const { y } = useScroll();
return (
<div className="App" style={{ height: "1000vh" }}>
<h1 style={{ position: "fixed", color: y > 100 ? "red" : "blue" }}>
hello
</h1>
</div>
);
}
import { useEffect, useRef, useState } from "react";
import "./styles.css";
const useFullscreen = (callback) => {
const element = useRef();
const triggerFull = () => {
if (element.current) {
element.current.requestFullscreen();
if(callback && typeof callback === "function"){
callback(true);
}
}
};
const exitFull = () => {
document.exitFullscreen();
if(callback && typeof callback === "function"){
callback(false);
}
};
return { element, triggerFull, exitFull };
};
export default function App() {
const onFullS = (isFull) => {
console.log(isFull ? "We are Full" : "We are small");
}
const { element, triggerFull, exitFull } = useFullscreen(onFullS);
return (
<div className="App" style={{ height: "1000vh" }}>
<div ref={element}>
<img src="https://www.hongik.ac.kr/front/images/local/header_logo.png" />
<button onClick={exitFull}>Exit FullScreen</button>
</div>
<button onClick={triggerFull}>Make FullScreen</button>
</div>
);
}
import { useEffect, useRef, useState } from "react";
import "./styles.css";
const useNotification = (title, options) => {
if(!("Notification" in window)){
return;
}
const fireNotif = () => {
if(Notification.permission !== "granted"){
Notification.requestPermission().then(permission => {
if(permission === 'granted'){
new Notification(title. options);
}else{
return;
}
})
}else{
new Notification(title, options);
}
}
return fireNotif;
}
export default function App() {
const triggerNotif = useNotification("Can I steal your kimchi?");
return (
<div className="App" style={{ height: "1000vh" }}>
<h1>Hello</h1>
<button onClick={triggerNotif}>Hello</button>
</div>
);
}
import defaultAxios from "axios";
import { useEffect, useState } from "react";
const useAxios = (opts, axiosInstance = 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());
}
useEffect(() => {
axiosInstance(opts).then(data => {
setState({
...state,
loading:false,
data
});
})
.catch(error => {
setState({...state, loading:false, error})
})
}, [trigger]);
return {...state, refetch};
};
export default useAxios;
import { useEffect, useRef, useState } from "react";
import "./styles.css";
import useAxios from "./useAxios";
export default function App() {
const { loading, data, error, refetch } = useAxios({
url:
"https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json"
});
console.log(
`Loading : ${loading}, Data : ${JSON.stringify(data)}, Error : ${error}`
);
return (
<div className="App" style={{ height: "1000vh" }}>
<h1>{data && data.status}</h1>
<h2>{loading && "Loading..."}</h2>
<button onClick={refetch}>Refetch</button>
</div>
);
}
npm init
blahblah
여기는 나중에 필요하면 다시 찾아서 보자.