๋ณธ๋ฌธ์œผ๋กœ ๋ฐ”๋กœ๊ฐ€๊ธฐ

1. useMemo()

useMemo(() => value, deps), useMemo(fn, deps)

const memoizedValue = useMemo(()=>computedExpensiveValue(a,b),[a,b])

- ๋žœ๋”๋ง ๋  ๋•Œ๋งˆ๋‹ค ๊ฐ’์„ ๊ณ„์† ๊ณ„์‚ฐํ•˜์ง€ ์•Š๊ณ , ์ด์ „์— ๊ณ„์‚ฐ๋œ ๊ฐ’์„ ๋ฉ”๋ชจ์ด์ œ์ด์…˜ํ•˜์—ฌ ๋ถˆํ•„์š”ํ•œ ์—ฐ์‚ฐ์„ ์ค„์ธ๋‹ค.

- ์ƒˆ๋กญ๊ฒŒ ๊ณ„์‚ฐํ•˜๋Š” ๊ธฐ์ค€์€ ๋‘๋ฒˆ์งธ ์ธ์ž, dependency์— ์ ๋Š”๋‹ค.

import { useMemo, useState } from 'react';

const App = () => {
  console.log('๋ฆฌ๋žœ๋”๋ง');
  const [isOn, setIsOn] = useState(false);
  const [users, setUsers] = useState([
    { active: true },
    { active: true },
    { active: false },
  ]);

  const countActiveUser = () => {
    console.log('์‚ฌ์šฉ์ž ์ˆ˜ ์„ธ๋Š”์ค‘...');
    return users.filter((user) => user.active).length;
  };

  const count = useMemo(countActiveUser, [users]);

  return (
    <div>
      <h1>{`ํ™œ์„ฑ ์‚ฌ์šฉ์ž ์ˆ˜: ${count}`}</h1>
      <button onClick={() => setIsOn((isOn) => !isOn)}>๋ฆฌ๋žœ๋”๋ง ํ•˜๊ธฐ</button>
      <button
        onClick={() => {
          setUsers(Array.from(users).concat({ active: true }));
        }}
      >
        ์‚ฌ์šฉ์ž ์ถ”๊ฐ€ํ•˜๊ธฐ
      </button>
    </div>
  );
};

 

2. useCallback()

useMemo(() => fn, deps) ์™€ useCallback(fn, deps) ๋Š” ๊ฐ™๋‹ค.

- ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง๋  ๋•Œ ๋ถˆํ•„์š”ํ•˜๊ฒŒ ํ•จ์ˆ˜๊ฐ€ ๋‹ค์‹œ ์ƒ์„ฑ๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•œ๋‹ค.

- ํ•จ์ˆ˜ ์ƒ์„ฑ ์ž์ฒด๊ฐ€ ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๋Š” ๊ฒฝ์šฐ, ํ•จ์ˆ˜๋ฅผ ์ž์‹ ์ปดํฌ๋„ŒํŠธ์— props๋กœ ๋„˜๊ฒจ์ค„ ๋•Œ useCallback()์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

import { useState, useCallback } from 'react';

const App = () => {
  const [firstName, setFirstName] = useState('junha');
  const [lastName, setLastName] = useState('kim');
  // ์ด๋ฆ„๊ณผ ์„ฑ์ด ๋ฐ”๋€” ๋•Œ๋งˆ๋‹ค ํ’€๋„ค์ž„์„ ๋ฉ”๋ชจ์ด์ œ์ด์…˜

  const getfullName = useCallback(() => {
    return `${firstName} ${lastName}`;
  }, [firstName, lastName]);

  return (
    <>
      {getfullName()}
      <button onClick={() => setFirstName('์ค€ํ•˜')}>๋ฒ„ํŠผ</button>
    </>
  );
};
export default App;

 

3. useRef()

- DOM Element์— ์ ‘๊ทผ ํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋ฉฐ, getElementById()์™€ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ํ•œ๋‹ค.

- DOM Element์˜ ref ์†์„ฑ์„ ์ด์šฉํ•œ๋‹ค.

import { useRef } from 'react';

const App = () => {
  const inputRef = useRef(null);
  const focusHandler = () => {
    inputRef.current.focus();
  };
  const clickHandler = () => {
    inputRef.current.value += '๊ฐ’์ด ๋ฐ”๊ผˆ์–ด์šฉ';
  };
  return (
    <div>
      <input ref={inputRef} type='text' />
      <button onClick={clickHandler}>๊ฐ’ ๋ฐ”๊พธ๊ธฐ</button>
      <button onClick={focusHandler}>input์œผ๋กœ ํฌ์ปค์Šค</button>
    </div>
  );
};
export default App;

useRef์˜ ๋ฆฌํ„ด ๊ฐ’

- useRef์˜ ๋ฆฌํ„ด๊ฐ’์— current ์†์„ฑ์„ ์ด์šฉํ•˜์—ฌ DOM์„ ์ปจํŠธ๋กค ํ•  ์ˆ˜ ์žˆ๋‹ค.

- ์ด ๊ฐ’์€ ์ปดํฌ๋„ŒํŠธ ์ƒ์•  ์ฃผ๊ธฐ ๋‚ด์—์„œ ์œ ์ง€ํ•œ๋‹ค.

- useRef ๊ฐ์ฒด๊ฐ€ ๋ณ€๊ฒฝ๋˜์–ด๋„ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์žฌ๋ Œ๋”๋ง๋˜์ง€ ์•Š๋Š”๋‹ค.

 

4. useTitle

: title ํƒœ๊ทธ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๊ธฐ๋Šฅ

import { useEffect, useState } from "react";

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 titleUpdater = useTitle("Loading...");
  setTimeout(() => titleUpdater("home"), 3000);
  return <div>Hi</div>;
};

export default App;

 

5. useClick

: ํ•ด๋‹น element๋ฅผ ํด๋ฆญ ์‹œ ์ฃผ์–ด์ง„ callBackํ•จ์ˆ˜ ์ถœ๋ ฅํ•˜๊ธฐ

: useRef() ์‚ฌ์šฉ

import { useEffect, useState, useRef } from "react";

const useClick = (onClick) => {
  const element = useRef();
  useEffect(() => {
    if (element.current) {
      element.current.addEventListener("click", onClick);
    }
    return () => {
      element.current.removeEventListener("click", onClick);
    };
  });
  return element;
};

const App = () => {
  const sayHello = () => console.log("๊ทธ๊ฑธ ๋ˆ„๋ฅด๋ˆ„");
  const title = useClick(sayHello);
  return (
    <div className="APP">
      <h1 ref={title}>Click me</h1>
    </div>
  );
};

export default App;

 

6. useConfirm

: ๋ฉ”์„ธ์ง€๋ฅผ ํ™•์ธ์‹œ์ผœ์ฃผ๊ณ , ์‘๋‹ต์— ๋”ฐ๋ผ ์ฝœ๋ฐฑํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ
: ์‚ฌ์šฉ์ž๊ฐ€ ๋ฒ„ํŠผํด๋ฆญ ์ž‘์—… ์ „ ๋ฉ”์„ธ์ง€ ๋ณด์—ฌ์ฃผ๊ณ  ์‹ถ์„ ๋•Œ

const useConfirm = (message = "", callback, rejection) => {
  if (!callback || typeof callback !== "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 to delete the World?",
    deleteWorld,
    abort
  );
  return (
    <div className="APP">
      <button onClick={confirmDelete}>Delete the World</button>
    </div>
  );
};

export default App;

 

7. usePreventLeave

: ๋ฒ„ํŠผ์— ๋”ฐ๋ผ ์ด๋ฒคํŠธ๋ฆฌ์Šค๋„ˆ๋ฅผ ์ถ”๊ฐ€์‹œ์ผœ์ฃผ๋Š” ๊ธฐ๋Šฅ

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>
  );
};

export default App;

beforeunload

: allows you to execute a function before the window gets closed, or before the person leaves your page

 

8. useBeforeLeave

: ๋งˆ์šฐ์Šค๊ฐ€ ํŽ˜์ด์ง€๋ฅผ ๋ฒ—์–ด๋‚˜๋ฉด ์‹คํ–‰์‹œํ‚ค๋Š” ๊ธฐ๋Šฅ

 

Cleanup Function

useEffect์—์„œ returnํ•œ ํ•จ์ˆ˜๋Š” componentWillUnmount ๋•Œ ํ˜ธ์ถœ๋œ๋‹ค.

์ด๋ฒคํŠธ๋ฆฌ์Šค๋„ˆ๊ฐ€ ํ˜ธ์ถœ๋˜๊ฑฐ๋‚˜ ์—…๋ฐ์ดํŠธ๋  ๋•Œ๋งˆ๋‹ค ์ด๋ฒคํŠธ๋ฆฌ์Šค๋„ˆ๊ฐ€ add๋˜๋Š”๊ฑธ ์›ํ•˜๋Š”๊ฒŒ ์•„๋‹ˆ๋‹ค.  ๊ณ ๋กœ dependency๋Š” []๋กœ didmount๋ ๋•Œํ•œ๋ฒˆ๋งŒ ํ˜ธ์ถœํ•˜๊ณ , willunmount๋  ๋•Œ ํด๋ฆฐ์—…ํ•จ์ˆ˜๋กœ ๋ฆฌํ„ด ํ•จ์ˆ˜๋กœ ์จ์ฃผ์ž

import { useEffect } from "react";

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", handle);
  }, []);
};

const App = () => {
  const sayHello = () => console.log("๋– ๋‚˜์ง€๋งˆ์šฉ");
  useBeforeLeave(sayHello);
  return (
    <div className="APP">
      <h1>Hello</h1>
    </div>
  );
};

export default App;

 

9. useFadein

component์˜ reference๋ฅผ ์–ป๋Š” ๋ฐฉ๋ฒ•์ด ํŠน์ดํ•˜๋‹ค.

 

useXXXํ•จ์ˆ˜์— useRef()๋ฅผ ์„ค์ •ํ•˜๊ณ  ๋‹ค์‹œ element returnํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ํ•ด๋‹น element๋ฅผ ์กฐ์ž‘ํ•œ๋‹ค. ์ด ๋ฐฉ๋ฒ•์ด ํšจ์œจ์ ์ธ ์ด์œ ๋Š” ๋ญ˜๊นŒ?  : ์˜ˆ๋ฅผ๋“ค์–ด fadeinํšจ๊ณผ๋ฅผ ์ฃผ๊ธฐ ์œ„ํ•ด์„œ, const el = useFadeIn()์„ ์ผ๋‹ค๊ณ  ํ•ด๋ณด์ž.  ๊ทธ๋Ÿผ fadeinํšจ๊ณผ๋ฅผ ์ฃผ๊ณ  ์‹ถ์€ ํƒœ๊ทธ์— ref={el}๋งŒ ๋„ฃ์œผ๋ฉด ๋ฐ”๋กœ ๊ทธ element๋ฅผ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค. ํ•˜๋‚˜ ์•Œ์•„๋‘ฌ์•ผํ•  ๊ฒƒ์€ html์š”์†Œ๋ฅผ ์กฐ์ž‘ํ•˜๊ธฐ ์œ„ํ•ด js๋ถ€๋ถ„์€ ํ•จ์ˆ˜๋กœ ๋ชจ๋“ˆํ™”์‹œํ‚ค๊ณ , ์ ์šฉํ•  ๋•Œ๋Š” htmlํƒœ๊ทธ์— ๋ฏธ๋ฆฌ ์„ ์–ธํ•ด๋‘” ๋ณ€์ˆ˜์ด๋ฆ„๋งŒ prop์— ๋„ฃ์œผ๋ฉด ๋œ๋‹ค๋Š” ๊ฒƒ. ์ด ๋””์ž์ธํŒจํ„ด์ด ํšจ์œจ์ ์œผ๋กœ ๋ณด์ด๊ธดํ•œ๋‹ค. ์™œ๋ƒ๋ฉด vanilia js์—์„œ ์ž‘๋™์‹œํ‚ฌ ๋•Œ๋Š” ์ •ํ•ด์ง„ ๊ทœ๊ฒฉ์ด ์—†์–ด์„œ ์‚ฐ๋ฐœ์ ์œผ๋กœ ์จ์ ธ์žˆ์—ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. 

 

import { useEffect, useRef } from "react";

const useFadeIn = (duration = "1") => {
  const element = useRef();
  useEffect(() => {
    if (element.current) {
      const { current } = element;
      current.style.transition = `opacity ${duration}s`;
      current.style.opacity = 1;
    }
  }, []);
  return { ref: element, style: { opacity: 0 } };
};

const App = () => {
  const fadeIn3s = useFadeIn(2);
  const fadeIn7s = useFadeIn(7);
  return (
    <div className="APP">
      <h1 {...fadeIn3s}>Hello</h1>
      <h5 {...fadeIn7s}>MR. JUNHA</h5>
    </div>
  );
};

export default App;

 

10. useNetwork

import { useEffect, useState } from "react";

const useNetwork = (onChange) => {
  const [status, setStatus] = useState(navigator.onLine);
  const handleChange = () => {
    setStatus(navigator.onLine);
    onChange(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 ? "Online" : "Offline");
  };
  const onLine = useNetwork(handleNetworkChange);
  return (
    <div className="APP">
      <h1>{onLine ? "Online" : "Offline"}</h1>
    </div>
  );
};

export default App;

navigator.onLine
- Tells you true or false if your website is online
It's always good to think "maybe people wouldn't just do this" when you're making a library for other people

 

11. useNotification

import { useEffect, useState, useRef } from "react";

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;
};

const App = () => {
  const triggerNotif = useNotification("Enter Summoner", {
    body: "Explore the World that you dream"
  });
  return (
    <div className="APP">
      <button onClick={triggerNotif}>Hello</button>
    </div>
  );
};

export default App;

 

12. useAxios

: about httpRequest

import React from "react";
import useAxios from "./useAxios";

const App = () => {
  const { loading, data, error, refetch } = useAxios({
    url: "https://yts.mx/api/v2/list_movies.json"
  });
  console.log(
    `Loading: ${loading}\nError:${error}\nData:${JSON.stringify(data)}`
  );

  return (
    <div>
      <h1>{data && data.status}</h1>
      <h2>{loading && "Loading"}</h2>
      <button onClick={refetch}>Refetch</button>
    </div>
  );
};
export default App;
import defaultAxios from "axios";
import { useState, useEffect } from "react";

const useAxios = (options, axiosInstance = defaultAxios) => {
  const [state, setState] = useState({
    loading: true,
    error: null,
    data: null
  });
  const [trigger, setTrigger] = useState(0);
  if (!options.url) {
    return;
  }
  const refetch = () => {
    setState({
      ...state,
      loading: true
    });
    setTrigger(Date.now());
  };
  useEffect(() => {
    axiosInstance(options)
      .then((data) => {
        setState({
          ...state,
          loading: false,
          data
        });
      })
      .catch((error) => {
        setState({
          ...state,
          loading: false,
          error
        });
      });
  }, [trigger]);
  return { ...state, refetch };
};

export default useAxios;


More about Hooks

More about 

https://sangcho.tistory.com/entry/ReactHooks%EC%9D%98%EB%B9%99%EC%82%B0

 

React Hooks์˜ ์ปค๋‹ค๋ž€ ๋น™์‚ฐ

* ์ด ๊ธ€์€ Iceberg of React Hooks ๋ฒˆ์—ญํ•˜์˜€์Šต๋‹ˆ๋‹ค. The Iceberg of React Hooks React Hooks, unlike Class Components, provide low-level building blocks for optimizing and composing applications with m..

sangcho.tistory.com

 

๋ฐ˜์‘ํ˜•