새소식

개발+공부/웹

#2-1 USEEFFECT

  • -
728x90

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, 사람들이 닫는 걸 신경쓰지 않아도 된다.

Prevent되는 모습

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이 되는 것을 막아준다.

CodeSandbox에서 네트워크가 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>
  );
};

CodeSandBox에서의 실행 결과

 

728x90

'개발+공부 > ' 카테고리의 다른 글

[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
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.