13.Custom Hooks

Updated:


웹 사이트에서 자주 작동하는 기능들을 custom hooks 로 제작하여 yarn, npm 설치가 가능하도록 publish 하였습니다.

jacob-hooks document

Hook Description Documentation NPM Page Yarn Page
useTitle Update your document’s title. Documentation NPM Page yarn Page
useScroll React Hook to get X/Y coordinates of current position of the scroll. Documentation NPM Page yarn Page
usePreventLeave React Hook to prompt the user for confirmation before leaving the page. Useful when changes haven’t been saved. Documentation NPM Page yarn Page
useNetwork React Hook to listen when the user goes online or offline. Documentation NPM Page yarn Page
useInput React Hook to update input event Documentation NPM Page yarn Page
useHover React Hook to detect a hover on an any React Element Documentation NPM Page yarn Page
useFadeIn React Hook to fade in any element. Documentation NPM Page yarn Page
useConfirm React Hook to ask the user for a confirmation before executing a function. Documentation NPM Page yarn Page
useClick React Hook to execute a function when the mouse click then add event listener Documentation NPM Page yarn Page
useBeforeLeave React Hook to execute a function when the mouse leaves the page. Useful to show a popup or for analytics. Documentation NPM Page yarn Page
useAxios React Hook to send HTTP request and get data from URL Documentation NPM Page yarn Page

1.useTitle

  • 인터넷 브라우저 창 위에 Title 을 변경하는 hooks

  • HTML Title 이 Loading… 이라고 mount 될때 실행되고 5초 후에 Home 으로 변경 시키는 useTitle 이용 예시

import React, { useEffect, useState } from "react";
import "./App.css";

// useTitle
const useTitle = (initialTitle) => {
  const [title, setTitle] = useState(initialTitle);
  const updateTitle = () => {
    const htmlTitle = document.querySelector("title");
    htmlTitle.innerText = title;
  };
  useEffect(updateTitle, [title]);
  return setTitle;
};

const App = () => {
  const titleUpdate = useTitle("Loading...");
  setTimeout(() => titleUpdate("Home"), 5000);
  return (
    <div className="App">
      <h1>Hello</h1>
    </div>
  );
};

export default App;

2.useScroll

  • 유저가 스크롤 해서 무언가를 지나갈때 색상을 바꾸거나 무언가를 할 수 있게 만들어 주는 hooks
// useScroll

const useScroll = () => {
  const [state, setState] = useState({
    x: 0,
    y: 0,
  });
  const onScroll = () => {
    setState({ y: window.scrollY, x: window.scrollX });
  };
  useEffect(() => {
    window.addEventListener("scroll", onScroll);
    // cleanUp
    return () => window.removeEventListener("scroll", onScroll);
  }, []);
  return state;
};

const App = () => {
  const { y } = useScroll();

  return (
    <div className="App" style=>
      <h1 style=>
        Hello
      </h1>
    </div>
  );
};

export default App;

3.usePreventLeave

  • 보통 웹사이트에서 만약 window 창을 닫을때 “아직 저장 되지 않았어!” 라고 메세지를 보낸때 사용되는 hooks

  • 또는 API 에 요청을 보냈는데 네트워크 속도가 느려서 아직 data 가 다 넘어 오지 않았는데 user 가 창을 닫거나 작업을 중단 시키려고 할때 작업이 다 끝나지 않았다로 알리는 message

const usePreventLeave = () => {
  const listener = (e) => {
    e.preventDefault();
    e.returnValue = "";
  };
  const enablePrevent = () => window.addEventListener("beforeunload", listener);
  const disenablePrevent = () =>
    window.removeEventListener("beforeunload", listener);

  return { enablePrevent, disenablePrevent };
};

const App = () => {
  const { enablePrevent, disenablePrevent } = usePreventLeave();
  return (
    <div className="App">
      <h1>Hello</h1>
      <button onClick={enablePrevent}>Protect</button>
      <button onClick={disenablePrevent}>Unprotected</button>
    </div>
  );
};

export default App;

4.useNetwork

  • useNetwork 는 offline 으로 네트워크로 변경할때 메세지를 호출하는 hooks
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);
    // clean Up
    return () => {
      window.removeEventListener("online", handleChange);
      window.removeEventListener("offline", handleChange);
    };
  }, []);

  return status;
};

const App = () => {
  const handleNetworkChange = (online) => {
    console.log(online ? "We are in onLine" : "OffLine check network");
  };
  const OnLine = useNetwork(handleNetworkChange);
  return (
    <div className="App">
      <h1>{OnLine ? "Online" : "Offline"}</h1>
    </div>
  );
};

export default App;

5.useInput

  • 기본적으로 input 을 업데이트 하는 hooks

  • initialValue, validator 를 parameter 를 받아서 input 창에서 10개 이상의 글자를 쓸 수 없게 하는 custom hooks

// useInput

const useInput = (initialValue, validator) => {
  const [value, setValue] = useState(initialValue);
  const onChange = (e) => {
    const {
      target: { value },
    } = e;
    let willUpdate = true;
    if (validator) {
      willUpdate = validator(value);
    }
    if (willUpdate) {
      setValue(value);
    }
  };
  return { value, onChange };
};

const App = () => {
  const maxLen = (value) => value.length <= 10;
  const name = useInput("Mr.", maxLen);

  return (
    <div className="App">
      <h1>Hello</h1>
      <input placeholder="Name" {...name} />
    </div>
  );
};

6.useHover

  • 마우스를 대상에 올려 놓게 되면 event 가 실행하는 hooks
// useClick
const useHover = (onHover) => {
  const element = useRef();
  useEffect(() => {
    if (element.current) {
      element.current.addEventListener("mouseenter", onHover);
    }
    // cleanUP
    return () => {
      if (element.current) {
        element.current.addEventListener("mouseenter", onHover);
      }
    };
  }, []);

  if (typeof onHover !== "function") {
    return;
  }
  return element;
};

const App = () => {
  const sayHello = () => console.log("Say Hello");

  const hover = useHover(sayHello);

  return (
    <div className="App">
      <h1>Hello</h1>
      <button ref={hover}>클릭</button>
    </div>
  );
};

export default App;

7.useFadeIn

  • 요소에 fade in 효과를 주는 hooks
// useFadeIn
const useFadeIn = (duration = 1, delay = 0) => {
  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;
    }
  }, []);
  if (typeof duration !== "number" || typeof delay !== "number") {
    return;
  }
  return { ref: element, style: { opacity: 0 } };
};

const App = () => {
  const fadeInH1 = useFadeIn(1, 2);
  const fadeInP = useFadeIn(5, 3);
  return (
    <div className="App">
      <h1 {...fadeInH1}>Hello</h1>
      <p {...fadeInP}>
        Lorem ipsum dolor sit amet consectetur adipisicing elit. Architecto
        aperiam minus accusamus ratione, necessitatibus sapiente! Ut mollitia at
        dolorum ea asperiores consectetur. Nostrum quo unde voluptates eveniet
        aliquam! Atque, dignissimos?
      </p>
    </div>
  );
};

export default App;

8.useConfirm

  • 사용자가 무언가를 하기전에 확인하는건데 만약 사용자가 버튼을 클릭하는 작업을 하면 (이벤트를 실행하기 전에) 메세지를 보여주고 싶은것 (alert 창에 정말로 삭제 하시겠습니까? 같은 것)
// useConfirm

const useConfirm = (message = "", onConfirm, onCancel) => {
  if (!onConfirm || typeof onConfirm !== "function") {
    return;
  }
  if (!onCancel || typeof onCancel !== "function") {
    return;
  }
  const confirmAction = () => {
    if (window.confirm(message)) {
      onConfirm();
    } else {
      onCancel();
    }
  };
  return confirmAction;
};

const App = () => {
  const deleteWorld = () => console.log("단어가 삭제되었습니다.");
  const abort = () => console.log("삭제가 취소 되었습니다.");
  const confirmDelete = useConfirm(
    "정말로 삭제하시겠습니까?",
    deleteWorld,
    abort
  );
  return (
    <div className="App">
      <h1>Hello</h1>
      <button onClick={confirmDelete}>Click me</button>
    </div>
  );
};

export default App;

9.useClick

  • 마우스를 클릭하게 되면 event 가 실행하는 hooks
const useClick = (onClick) => {
  const element = useRef();

  useEffect(() => {
    if (element.current) {
      // 'click' is keyword
      element.current.addEventListener("click", onClick);
    }
    //  CleanUp ComponentWillUnmount()
    return () => {
      if (element.current) {
        element.current.removeEventListener("click", onClick);
      }
    };
  }, [onClick]);

  if (typeof onClick !== "function") {
    return;
  }
  return element;
};

const App = () => {
  const sayHello = () => console.log("Say Hello");

  const title = useClick(sayHello);

  return (
    <div className="App">
      <h1 ref={title}>Hello</h1>
    </div>
  );
};

10.useBeforeLeave

  • 기본적으로 탭을 닫을때 실행되는 function 팝업이나 특히 뭔가를 중지시키려고 할때 “나가지마요” 라고 라는 function 을 사용하는 hooks
// useBeforeLeave

const useBeforeLeave = (onBefore) => {
  const handle = (e) => {
    // clientY 마우스의 y 축의 위치 기준으로 0 보다 작은경우 함수 실행 (top 위치일때)
    const { clientY } = e;
    if (clientY <= 0) {
      onBefore();
    }
  };
  useEffect(() => {
    document.addEventListener("mouseleave", handle);
    // cleanUp
    return () => document.removeEventListener("mouseleave", handle);
  }, []);
  if (typeof onBefore !== "function") {
    return;
  }
};

const App = () => {
  const begForLife = () => console.log("Pls don't leave");
  useBeforeLeave(begForLife);
  return (
    <div className="App">
      <h1>Hello</h1>
    </div>
  );
};

export default App;

11.useAxios

  • HTTP request 를 만드는 hooks
import React, { useEffect, useState } from "react";
import defaultAxios from "axios";
import "./App.css";

// useAxios

const useAxios = (opts, axiosInstance = defaultAxios) => {
  const [state, setState] = useState({
    loading: true,
    error: null,
    data: null,
  });
  const [trigger, setTrigger] = useState(0);
  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]);

  if (!opts.url) {
    return;
  }

  return { ...state, refetch };
};

const App = () => {
  const { loading, data, refetch } = useAxios({
    url: "https://yts.mx/api/v2/list_movies.json",
  });
  return (
    <>
      <div className="App">
        <h1>{data && data.status}</h1>
        <h2>{loading && "Loading"}</h2>
        <button onClick={refetch}>Refetch</button>
      </div>
    </>
  );
};

export default App;

🔶 🔷 📌 🔑

Reference

Categories:

Updated:

Leave a comment