2.0 Introduction to useEffect
useEffect
componentDidmount의 역할을 해서 새로고침하면 sayHello를 실행한다.
2개 인자를 받음
- function으로서의 effect
- dependency
: 만약 deps가 있다면 effect (deps)리스트에 있는 값일 때만 값이 변하도록 활성화 된다.
useEffect는 여기서 componentDidMount, componentWillUpdate이다.
dependency일 때만 update한다.
📌 dependency에 change가 발생할 때만 update!
+ useEffect로부터 function이 return된다. -> componentWillUnmount!
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
const App = () => {
const sayHello = () => console.log("hello");
const [number, setNumber] = useState(0);
const [aNumber, setAnumber] = useState(0);
useEffect(sayHello, [number]);
return (
<div className="App">
<div>Hi</div>
<button onClick={() => setNumber(number + 1)}>{number}</button>
<button onClick={() => setAnumber(aNumber + 1)}>{aNumber}</button>
</div>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
🚩 정리
useEffect(sayHello); // componentDidmount, componentWillUnmount, componentDidUpdate useEffect(sayHello, [dependency]); // dependency가 change할 때만, componentWillUpdate
2.1 useTitle
문서의 제목을 업데이트 시켜주는 걸 담당하는 hooks
- 보통 react의 helmet을 사용
- 우리는 functional hooks의 방식으로 만들어 보자
2.2 useClick
useRef
reference는 기본적으로 우리의 component의 어떤 부분을 선택할 수 있는 방법이다.
document.getElementById()를 사용한 것과 같다.
const App = () => {
const potato = useRef();
setTimeout(() => potato.current.focus(), 5000);
return (
<div className="App">
<div>Hi</div>
<input ref={potato} placeholder="la" />
</div>
);
};
<input>은 potato를 참조한다.
5초 후, input(potato)가 블록 처리 된다.
useClick
(useRef를 이용하여 구현)
: useEffect는 componentWillUnmount 때 발생
const useClick = (onClick) => {
const element = useRef();
useEffect(() => {
// mount시, 호출
if (element.current) {
element.current.addEventListener("click", onClick);
}
// componentWillUnmount시, 호출
return () => {
if (element.current){
element.current.removeEventListener("click", onClick);
}
}
}, []); // no dependency -> update되었을 때는 고려X
return element;
};
const App = () => {
const sayHello = () => console.log("hello");
const title = useClick(sayHello);
return (
<div className="App">
<h1 ref={title}>Hi</h1>
</div>
);
};
+ componentWillUnmount될 때, eventListener를 정리해줘야 한다.
📌 정리 ⭐⭐⭐⭐⭐
useEffect안에 function을 넣으면, 그 function은 dependency가 존재하지 않는 한, componentDidMount, componentDidUpdate 때 호출된다.
dependency가 존재한다면, componentDidMount일 때만 호출된다.
componentWillUnmount때, return을 한다. (useEffect의 return부분을 수행)
만약 function을 호출한다면, useEffect에서 return한 그 함수는 componentWillUnMount때 호출된다.
- unmounted component에 eventListenr가 배치되지 않게 하기 위해 이렇게 한다.
2.3 useConfirm & usePreventLeave
useConfirm
: 사용자가 무언가를 하기 전에 (확인)하는 것
const useConfirm = (message, callback, rejection) => {
if (!callback || typeof callback !== "function") {
return;
}
if (rejection && typeof rejection !== "function"){
return;
}
const confirmAction = () => {
if (confirm(message)) {
callback();
} else {
rejection();
}
};
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 the world</button>
</div>
);
};
💡 FLOW
- Delete the world버튼을 클릭하면, confrimDelete->useConfirm이 호출된다.
- useConfrim은 confirmAction을 return하고, confirmAction이 호출된다.
- message("Are you sure?")을 confrim(alert로 확인)한다.
- true라면, callback->deleteWorld을 호출한다.
- false라면, rejection->abort를 호출한다.
- deleteWorld가 console에 "Deleting the world..."(F: "Aborted") log를 남긴다.
- onConfirm(callback)은 필수/ onCancel(rejection)은 필수X
- 어떤 어려운 클릭의 결과라도 사용자를 보호할 수 있다.
usePreventLeave
: window창을 닫을 때, "아직 저장하지 않았습니다!"라고 뜨는 것
- hooks 사용을 전혀 요구하지 않는다.
1) enablePrevent
ex) API에서 뭔가 보냈고, 사람들이 닫지 않기를 원한다면, 이를 보호할 수 있게 활성화
BUT if API is ok, 사람들이 닫는 걸 신경쓰지 않아도 된다.
2) disablePrevent
: 보호X
const usePreventLeave = () => {
const listener = (event) => {
event.preventDefault();
event.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>
);
};
2.4 useBeforeLeave
useBeforeLeave
: 기본적으로 탭을 닫을 때 실행되는 function
hook을 사용한 useBeforeLeave 구현하기
const useBeforeLeave = (onBefore) => {
if (typeof onBefore !== "function") {
return;
}
const handle = () => {
onBefore();
};
useEffect(() => {
document.addEventListener("mouseleave", handle);
return () => document.removeEventListener("mouseleave");
}, []);
};
const App = () => {
const begForLife = () => console.log("Pls don't leave");
useBeforeLeave(begForLife);
return (
<div className="App">
<h1>Hello</h1>
</div>
);
};
Optimization
mouse가 위쪽 방향으로 벗어날 때만 onBefore함수를 실행하게 해보자.
const useBeforeLeave = (onBefore) => {
if (typeof onBefore !== "function") {
return;
}
const handle = (event) => {
const { clientY } = event;
if (clientY <= 0) {
onBefore();
}
};
useEffect(() => {
document.addEventListener("mouseleave", handle);
return () => document.removeEventListener("mouseleave");
}, []);
};
2.5 useFadeIn & useNetwork
useFadeIn
: element를 자동으로 서서히 나타나게(fade in) 한다.
+ css로 만들 수도 있다.
=> hooks와 animation을 섞을 수 있는 방법을 알아보자!
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 App = () => {
const fadeInH1 = useFadeIn(1, 2);
const FadeInP = useFadeIn(5, 10);
return (
<div className="App">
<h1 {...fadeInH1}>Hello</h1>
<p {...FadeInP}>lorem ipsum lalalala</p>
</div>
);
};
useNetwork
: navigator가 online 또는 offline이 되는 것을 막아준다.
called everytime network changes
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>
);
};
'💻 Study > 웹' 카테고리의 다른 글
[Javascript] '==' 와 '===' 뭐가 다를까? (0) | 2021.02.24 |
---|---|
#2-2 USEEFFECT (0) | 2021.01.12 |
#1 USESTATE (0) | 2021.01.12 |
#0 INTRODUCTION - 리액트 Hooks (0) | 2021.01.10 |
#6 ROUTING BONUS (0) | 2021.01.10 |