React Hooks | NomardCoder
✅Check
useTitle = react document의 title을 몇개의 hooks와 함께 바꾸는 것
useInput = 그냥 input 역할을 한다
usePageLeave = 유저가 page를 벗어나는 시점을 발견하고 함수를 실행
useClick = 누군가 element를 클릭하는 시점을 발견
useFadeIn = 어떤 elemet든 상관없이 애니메이션을 elemet안으로 서서히 사라지게 만듦
useFullscreen = elemet든 풀스크린으로 만들거나 일반화면으로 돌아가게
useHover = 어떤 화면에 마우스를 올렸을 때 감지
useNetwork = online offline 상태 감지
useNotification = notification API사용할때 유저에게 알림을 보내줌
useScroll = 스크롤 사용할떄 감지
useTabs = 웹사이트에 메뉴 또는 무엇이든간 tab을 사용하기 쉽게 만들어줌
usePreventLeave = 유저가 변경사항이나 무엇이든간 저장하지 않고 페이지를 벗어나길 원할 때 확인
useConfirm = 어떤 기능이 존재하고
useAxios = HTTP request client axios를 위한 wrapper 같은 것
- 사람들이 다운받아 사용할 수 있도록 NPM에 올려보기 - npm package에 등록하는 방법을 배울 것
- codeSandBox에서 시뮬 돌려보고 VSC에 정리
✔ useState
useInput
import React, { useState } from "react";
import "./styles.css";
const useInput = (initialValue, vaildator) => {
const [value, setValue] = useState(initialValue);
const onChange = (e) => {
const {
target: { value }
} = e;
//유효성검사
let willUpdate = true;
if (typeof vaildator === "function") {
willUpdate = vaildator(value);
}
if (willUpdate) {
setValue(value);
}
};
return { value, onChange };
};
const App = () => {
const maxLen = value => value.length < 10;
const name = useInput("hy", maxLen);
return (
<div className="App">
<h1>Hello</h1>
<input placeholder="name" {...name} />
</div>
);
};
export default App;
useTabs
import React, { useState } from "react";
const content = [
{
tab : "section1",
desc : "i'm the content of the section 1"
},
{
tab : "section2",
desc : "i'm the content of the section 2"
}
]
//useTab hook
const useTabs = (initialTab, allTabs) => {
//에러확인하기) content없거나, 배열이 아닐때 return
if(!allTabs || !Array.isArray(allTabs)){
return;
}
const [currentIndex, setCurrentIndex] = useState(initialTab);
return{
currentItem: allTabs[currentIndex],
changeItem: setCurrentIndex
}
}
const App = () => {
const {currentItem, changeItem} = useTabs(0, content);
return(
<div className="App">
{content.map((item, index) =>
<button onClick={()=>{changeItem(index)}}>{item.tab}</button>
)}
<div>{currentItem.desc}</div>
</div>
)
}
export default App;
✔ useEffect
- useEffect는 componentDidMount, componentWillUnMount, componentDidUpdate
- 2개의 인자를 받음
(첫번째는 function으로서의 effect, 두번째는 dependency의 deps)
- deps가 있다면 effect는 deps 리스트에 있는 값일 때만 값이 변하도록 활성화된다.
- 계속해서 이벤트가 추가되는 것을 막아줌 ([ ])
useTitle
- tab title을 바꿔주는 hook
import React, { useState, useEffect } from "react";
import "./styles.css";
const useTitle = (initialTitle) => {
const [title, setTitle] = useState(initialTitle);
const updateTitle = () => {
const htmlTitle = document.querySelector("title");
htmlTitle.innerHTML = title;
};
useEffect(updateTitle, [title]);
return setTitle;
}
const App = () => {
const titleUpdater = useTitle("Loading...");
setTimeout(()=>titleUpdater("home"), 3000)
return (
<div className="App">
<h1>Hello</h1>
</div>
);
}
export default App;
✔ useRef
- reference는 기본적으로 우리의 component의 어떤 부분을 선택할 수 있는 방법 -> document.getElementByID( )와 동등
- react에 있는 모든 component는 reference element를 가지고 있음 (reference prop)
useClick
import React, { useState, useEffect, useRef } from "react";
const useclick = onclick => {
if(typeof onclick !== 'function'){
return;
}
const element = useRef();
useEffect(() => {
//useEffect가 mount, update 되었을 때
if(element.current){
element.current.addEventListener("click",onclick);
}
//useEffect componentWillUnMount시
return () => {
if(element.current){
element.current.removeEventListener("click",onclick);
}
}
//dependency없음 = (update시 고려해야할 사항 없음) = [ ]
}, [])
return element;
}
export default function App() {
const say = () => console.log("say!!!!!say!!!!!")
const title = useclick(say);
return (
<div className="App">
<h1 ref={title}>Hello</h1>
</div>
);
}
- useEffect에 function을 넣으면, componentDidMount, componentWillUnMount 때 호출 됨 (dependency가 존재하지 않는 한)- dependency가 존재한다면, useEffect 안 function은 componentDidMount일 때만 호출 됨.
- function을 return 받았다면, 그 function은 componentWillUnMount로 부터 호출된 것.
*useEffect가 mount시, unmount시- componentWillUnMount 될 때, addEventListener를 지워야한다-> useEffect는 componentDidMount상태에 동작함-> componentWillUnMount일 때 ,이벤트가 발생한 뒤 정리할 필요가 있음. => function을 return 시켜줌-> removeEventListener
useHover
import React, { useEffect, useRef } from "react";
import "./styles.css";
const useHover = onHover => {
if(typeof onHover !== "function"){
return;
}
const element = useRef();
useEffect(() => {
if(element.current){
element.current.addEventListener("mouseenter", onHover);
}
return () => {
if(element.current){
element.current.removeEventListener("mouseenter",onHover);
}
}
},[])
return element;
}
const App = () => {
const say = () => console.log("hover");
const title = useHover(say);
return (
<div className="App">
<h1 ref={title}>Hello</h1>
</div>
);
}
export default App;
- useClick과 비슷, addEventListener의 event type을 click -> mouseenter로 변경
useConfirm & usePreventLeave
- 위 두개는 실제로 hook이 아니다. useState와 useEffect를 사용하지 않고 만들것이기 때문.
useConfirm
import React from "react";
const useConfirm = (message, callback, reject) => {
if (!callback && typeof callback !== "function") {
return;
}
if (reject && typeof reject !== "function") {
return;
}
const confirmAction = () => {
if (confirm(message)) {
callback();
} else {
reject();
}
};
return confirmAction;
};
const App = () => {
const deleteWorld = () => console.log("Deleting the world");
const abort = () => console.log("Aborted");
const confirmDelete = useConfirm("Are you sure?", deleteWorld, abort);
return (
<div className="App">
<button onClick={confirmDelete}>Delete your desc</button>
</div>
);
};
export default App;
- confirmDelete가 실제로는 confirmAction과 같음
usePreventLeave
import React from "react";
const usePreventLeave = () => {
const listener = (e) => {
e.preventDefault();
e.returnValue = '';
} ;
const enablePrevent = () => window.addEventListener("beforeunload",listener);
const disablePrevent = () => window.removeEventListener("beforeunload",listener);
return { enablePrevent, disablePrevent };
}
const App = () => {
const {enablePrevent, disablePrevent} = usePreventLeave();
return (
<div className="App">
<button onClick={enablePrevent}>protect</button>
<button onClick={disablePrevent}>unprotect</button>
</div>
);
};
export default App;
useBeforeLeave
import React, { useState, useEffect, useRef } from "react";
const useBeforeLeave = onBefore => {
if(typeof onBefore !== 'function'){
return;
}
const handler = () => {
onBefore();
}
useEffect(() => {
document.addEventListener("mouseleave", handler);
return () => document.removeEventListener("mouseleave",handler);
},[])
}
const App = () => {
const desc = () => console.log("Don't leave me ㅠㅠ");
useBeforeLeave(desc);
return (
<div className="App">
<h1>Hello</h1>
</div>
);
};
export default App;
useFadeIn
import React, { useState, useEffect, useRef} 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 ${delay}s ease-in-out`;
current.style.opacity = 1;
}
}, [])
// return element;
return {ref:element, style:{opacity:0}};
}
const App = () => {
// const el = useFadeIn();
const fadeInH1 = useFadeIn(2,1);
const fadeInP = useFadeIn(2,2);
; return (
<div className="App">
{/* <h1 ref={el} style={{opacity:0}}>Hello</h1> */}
<h1 {...fadeInH1}>Hello</h1>
<p {...fadeInP}>lorem brbrbr</p>
</div>
);
}
export default App;
- duration=1, delay=0은 기본 값
- hooks와 animation을 섞어보기
useNetwork
import React, { useState, useEffect, useRef } from "react";
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);
() => {
window.removeEventListener("online",handleChange);
window.removeEventListener("offline",handleChange);
};
},[]);
return status;
};
const App = () => {
const handleNetworkChange = onLine => {
console.log(onLine ? 'we just went online' : 'we are offline');
}
const onLine = useNetwork(handleNetworkChange);
return (
<div className="App">
<h1>{onLine ? 'onLine' : 'offLine'}</h1>
</div>
);
}
export default App;
- navigator가 online또는 offline 되는걸 막아준다. -> 확인시켜줌
useScroll
- 유저가 스크롤해서 무언갈 지나쳤을 때, 색상을 바꾸거나 무엇이든 해주는 기능
import React, { useState, useEffect, useRef } from "react";
const useScroll = () => {
const [state, setState] = useState({ x: 0, y: 0 });
const onScroll = () => {
setState({x:window.screenX, y:window.scrollY})
}
useEffect(()=>{
window.addEventListener("scroll",onScroll);
return () => {
window.removeEventListener("scroll",onScroll);
}
},[])
return state;
};
const App = () => {
const { y } = useScroll();
return (
<div className="App" style={{height:'1000vh'}}>
<h1 style={{ position: 'fixed', color: y > 100 ? "red" : "blue" }}>Hello</h1>
</div>
);
};
export default App;
useFullscreen
import React, { useState, useEffect, useRef } from "react";
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://docs.microsoft.com/ko-kr/windows/uwp/design/controls-and-patterns/images/image_licorice.jpg"/>
</div>
<button onClick={triggerFull}>full btn</button>
<button onClick={exitFull}>exit btn</button>
</div>
);
}
↓ 브라우저 호환성에 따른 Fullscreen API
import React, { useState, useEffect, useRef } from "react";
const useFullscreen = callback => {
const element = useRef();
const runCb = isFull => {
if(callback && typeof callback === 'function'){
callback(isFull);
}
};
//브라우저 호환성
const triggerFull = () => {
if(element.current){
if(element.current.requestFullscreen){
element.current.requestFullscreen();
//firefox
}else if(element.current.mozRequestFullScreen){
element.current.mozRequestFullScreen();
//opera
}else if(element.current.webkitRequestFullscreen){
element.current.webkitRequestFullScreen();
//ms
}else if(element.current.msRequestFullscreen){
element.current.msRequestFullscreen();
}
runCb(true);
}
};
//브라우저 호환성
const exitFull = () => {
document.exitFullscreen();
if(document.exitFullscreen){
document.exitFullscreen();
//firefox
}else if(document.mozRequestFullScreen){
document.mozCancelFullScreen();
//opera
}else if(document.webkitRequestFullscreen){
document.webkitExitFullScreen();
//ms
}else if(document.msRequestFullscreen){
document.msExitFullscreen();
}
runCb(false);
};
return { element, triggerFull, exitFull };
};
const 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://docs.microsoft.com/ko-kr/windows/uwp/design/controls-and-patterns/images/image_licorice.jpg"/>
</div>
<button onClick={triggerFull}>full btn</button>
<button onClick={exitFull}>exit btn</button>
</div>
);
};
export default App;
useNotification
import React, { useState, useEffect, useRef } from "react";
const useNotification = (title, option) => {
if (!("notification" in window)) {
return;
}
const fireNotif = () => {
if (Notification.permission !== "granted") {
Notification.requestPermission().then((permission) => {
if (permission === "granted") {
new Notification(title, option);
} else {
return;
}
});
} else {
new Notification(title, option);
}
};
return fireNotif;
};
const App = () => {
const triggerNotif = useNotification("yaya");
return (
<div className="App">
<button onClick={triggerNotif}>hello</button>
</div>
);
};
export default App;
useAxios
- HTTP request를 만드는 것
- axios는 customization과 configuration을 허용
(ex) axios는 default URL을 설정하거나 자동으로 헤더를 설정하는 거 과 같은 것들을 허용함)
import React, { useState, useEffect, useRef} from "react";
import defaultAxios from 'axios';
const useAxios = (opts, axiosInstance = defaultAxios) => {
const [state, setState] = useState({
loading : true,
error: null,
data:null
});
if(!opts.url){
return;
};
useEffect(() => {
axiosInstance(opts).then(data => {
setState({
...state,
loading:false,
data
});
}).catch(error => {
setState({
...state,
loading:false,
error
})
})
},[]);
return state;
}
const App = () => {
const { loading, error, data } = useAxios({url:"https://yts.mx/api/v2/list_movies.json"});
console.log(loading, error, JSON.stringify(data));
return (
<div className="App">
<h1>Hello</h1>
</div>
);
}
export default App;
- useEffect로 axios 부르기, dependency를 빈값으로 둬서 update로 부터 보호
- axios는 data를 성공적으로 받으면 then, error가 생기면 catch
'React' 카테고리의 다른 글
React에서 'onClick' Event 실행해보기 (0) | 2020.12.09 |
---|---|
Movie-app (0) | 2020.11.26 |
React Hooks 간단 예습 (0) | 2020.11.07 |
Lifecycle Methods to Class (0) | 2020.11.05 |
react 추가 study (0) | 2020.11.04 |