/lecture_react_hooks

๐Ÿ“– Lecture NOMAD React Hooks

Primary LanguageJavaScript

NOMAD REACT HOOK Lecture

1.0 Introduction to useState

const Hook1 = () => {
  const [count, setCount] = useState(1);
  const plus = () => setCount(count + 1);
  const minus = () => setCount(count - 1);
  return (
    <>
      <div>{count}</div>
      <button onClick={plus}>+</button>
      <button onClick={minus}>-</button>
    </>
  );
};

1.1 useInput

const useInput = (initialState) => {
  const [value, setValue] = useState(initialState);
  const onChange = (e) => {
    console.log(e.target.value);
    setValue(e.target.value);
  };
  return { value, onChange };
};
const Hook2 = () => {
  const name = useInput("Mr.");
  return (
    <>
      <div>HI</div>
      <input placeholder="" {...name}></input>
    </>
  );
};

1.2 useInput part Two

const useInputVaild = (initialState, vaildator) => {
  const [value, setValue] = useState(initialState);
  const onChange = (e) => {
    let willupdate = true;
    console.log(e.target.value);
    if (typeof vaildator === "function") {
      willupdate = vaildator(e.target.value);
    }
    if (willupdate) {
      setValue(e.target.value);
    }
  };
  return { value, onChange };
};

const Hook3 = () => {
  const name = useInputVaild("Mr.", (v) => v.length <= 10);
  return (
    <>
      <div>
        <input placeholder="" {...name}></input>
      </div>
    </>
  );
};

1.3 useTabs

const AJAXData = [
  {
    title: "Section-1",
    content: "This is Section - 1 Content",
  },
  {
    title: "Section-2",
    content: "This is Section - 2 Content",
  },
  {
    title: "Section-3",
    content: "This is Section - 3 Content",
  },
];
//์ž…๋ ฅ : ์ดˆ๊ธฐ ํƒญ์ธ๋ฑ์Šค/๋ฐฐ์—ด ๋ฐ์ดํ„ฐ : ์ถœ๋ ฅ ํ˜„์žฌ ์ฝ˜ํ…์ธ  ๋ฐ ์ธ๋ฑ์Šค ๋ณ€๊ฒฝํ•จ์ˆ˜
const useTabs = (initIdx, arrayData) => {
  const [idx, setIdx] = useState(initIdx);
  if (!Array.isArray(arrayData)) {
    return;
  }

  return { data: arrayData[idx], setIdx };
};

const Hook4 = () => {
  const sectionTab = useTabs(0, AJAXData);
  return (
    <>
      {AJAXData.map((e, i) => (
        <button onClick={() => sectionTab.setIdx(i)}>{e.title}</button>
      ))}
      <div>{sectionTab.data.content}</div>
    </>
  );
};

2 useEffect

  • useEffect : ๋ฌด์กฐ๊ฑด ์‹คํ–‰๋˜๋Š” ์‚ฌ์ด๋“œ ์ดํŒฉํŠธ | ํ•œ๋ฒˆ๋งŒ ์‹คํ–‰๋˜๋Š” ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ | ํŠน์ • ๋ณ€์ˆ˜๊ฐ€ ๋ฐ”๋€Œ๋ฉด ์‹คํ–‰๋˜๋Š” ์ดํŽ™ํŠธ
  • ์ฝ”๋“œ๋Š” ์œ„์—์„œ ์•„๋ž˜๋กœ ์‹คํ–‰๋œ๋‹ค. | useEffect๊ฐ€ ์ถ”์ ํ•˜๋Š” ๋ณ€์ˆ˜๊ฐ€ useEffect ์ฝ”๋“œ์•„๋ž˜์— ์žˆ๋‹ค๋ฉด ๋ฌด์šฉ์ง€๋ฌผ
  • ๋žœ๋”๋ง ํ์— ํ•œ๋ฒˆ์— ๋ชจ์•˜๋‹ค๊ฐ€ ์‹คํ–‰๋œ๋‹ค.3
useEffect(() => {
  console.log("cnt Changed");
});

useEffect(() => {
  console.log("cnt Changed");
}, []);

useEffect(() => {
  console.log("cnt Changed");
}, [cnt]);

useEffect(() => {
  D.addEventLisenter("click", e);
  return () => {
    D.removeEventLisenter("click", e);
  };
}, [D]);

2.1 useTitle

//์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋กœ ๋ฌธ์„œ์˜ title๋ฅผ ๋ณ€๊ฒฝํ•œ๋‹ค.
const useTitle = (initalTitle) => {
  const [title, setTitle] = useState(initalTitle);
  useEffect(() => {
    const htmlTitle = document.querySelector("title");
    htmlTitle.innerText = title;
  }, [title]);
  return setTitle;
};

const Hook6 = () => {
  const titleUpdator = useTitle("DOSIMPACT");
  setTimeout(() => titleUpdator("BOOM!!"), 3000);
  return <></>;
};

2.2 useClick

  • useRef ๋Š” getElementByIdํ•ด์„œ ๊ฐ€์ ธ์˜จ ํƒœ๊ทธํ•ธ๋“ค๋Ÿฌ์™€ ๋น„์Šทํ•˜๋‹ค.
const Hook7 = () => {
  const nameInputRef = useRef();
  setTimeout(() => nameInputRef.current && nameInputRef.current.focus(), 1000);
  return (
    <div>
      <input ref={nameInputRef} placeholder="name"></input>
    </div>
  );
};

2.3 useConfirm & usePreventLeave

//ํŠน์ • HTML ์— > ํด๋ฆญ์„ ํŠธ๋ฆฌ๊ฑฐ๋กœ > ํŠน์ • ํ•จ์ˆ˜ ์‹คํ–‰
const useClick = (onClick) => {
  const element = useRef();
  useEffect(() => {
    const HTMLHandler = element.current;
    if (HTMLHandler) {
      HTMLHandler.addEventListener("click", onClick);
    }
    return () => {
      HTMLHandler.removeEventListener("click", onClick);
    };
  }, [onClick]);
  return element;
};

const Hook8 = () => {
  const sayHello = () => console.log("helllo");
  const title = useClick(sayHello);
  return (
    <div>
      <h2 ref={title}>TITLE</h2>
    </div>
  );
};

2.4 useBeforeLeave

  • 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 Hook9 = () => {
  const deleteWorldConfirm = () => console.log("DELETE WORLD Suc");
  const deleteWorldDelete = () => console.log("DELETE WORLD Fail");
  const confirmDelete = useConfirm(
    "Sure? ",
    deleteWorldConfirm,
    deleteWorldDelete
  );

  return (
    <div>
      <button onClick={confirmDelete}>DELETE</button>
    </div>
  );
};
  • ์ฐฝ ๋‹ซ๊ธฐ์ „์— ํ™•์ธ
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 Hook10 = () => {
  const { enablePrevent, disablePrevent } = usePreventLeave();
  return (
    <>
      <div>
        <button onClick={enablePrevent}>Protect</button>
        <button onClick={disablePrevent}>unProtect</button>
      </div>
    </>
  );
};
const useBeforeLeave = (onBefore) => {
  // if (typeof onBefore !== "function") {
  //   return;
  // }

  useEffect(() => {
    const handle = () => {
      onBefore();
    };
    document.addEventListener("mouseleave", handle);
    return () => document.removeEventListener("mouseleave", handle);
  }, [onBefore]);
};

const Hook11 = () => {
  const beggingYou = () => console.log("please dont leave me..");
  useBeforeLeave(beggingYou);
  return <div>BEGGING</div>;
};

2.5 useFadeIn & useNetwork

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

const Hook12 = () => {
  const titleFadein = useFadeIn();
  return (
    <>
      <h2 {...titleFadein}>DOS-IMPACT</h2>
    </>
  );
};

2.6 useScroll & useFullscreen

// ๋‹จ์ˆœํ•˜๊ฒŒ ํ˜„์žฌ์˜ ์Šคํฌ๋กค ์œ„์น˜๋ฅผ ๋ฐ˜ํ™˜ํ•ด ์ค€๋‹ค.
const useScroll = () => {
  const [state, setState] = useState({
    x: 0,
    y: 0,
  });
  const onScroll = () => {
    setState({ y: window.scrollY, x: window.scrollX });
  };
  useEffect(() => {
    window.addEventListener("scroll", onScroll);
    return () => window.removeEventListener("scroll", onScroll);
  }, []);

  return state;
};

const Hook14 = () => {
  const position = useScroll();
  return <>{JSON.stringify(position)}</>;
};

2.7 useNotification

2.8 useAxios

2.9 Conclusions

https://reactjs.org/docs/hooks-faq.html#how-can-i-do-data-fetching-with-hooks

  • ํ›… ๊ทœ์น™ ๋ณผ๊ฒƒ!!

useEffect์—์„œ ์—ฌ๋Ÿฌ๋ฒˆ setState๋ฅผ ํ•˜๋ฉด ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ

  • useEffect์˜ ๋žœ๋”๋ง ์‚ฌ์ดํด ์ดํ•ด ์•„์ง X

  • try ์—์„œ data๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ , setState๋กœ data๋ฅผ ์ €์žฅํ•˜๋Š” ์ˆœ๊ฐ„, useEffect ๊ตฌ๋ฌธ์—์„œ ๋น„๋™๊ธฐ์ ์œผ๋กœ ๋žœ๋”๋ง์ด ๋จ ( data๊ฐ€ ์ž˜ ๋“ค์–ด์˜ด )

  • finally ์—์„œ loading์„ false๋กœ ๋ฐ”๊พธ๋Š” ์ˆœ๊ฐ„, ์›๋ž˜ data๊ฐ€ ์—†๋˜ ์ดˆ๊ธฐ์ƒํƒœ์˜ state์— loading๋งŒ false๋กœ ๋žœ๋”๋ง์ด ํ•œ๋ฒˆ ๋” ๋˜๋Š”๋“ฏ.

  • ๋ฌธ์ œ์˜ ์ฝ”๋“œ

const useAxios = (opts, axiosInstance = defaultAxios) => {
  const [state, setState] = useState({
    loading: true,
    erorr: false,
    data: null,
  });
  const [trigger, setTrigger] = useState(false);

  const triggerRefectch = () => {
    setTrigger(!trigger);
    setState({ ...state, loading: true });
  };

  useEffect(async () => {
    try {
      const { data } = await axiosInstance(opts);
      console.log("useEFFECT try : ");
      console.log(state);
      console.log(data);
      setState({ ...state, data });
    } catch (error) {
      setState({ error: true });
    } finally {
      //setState({ loading: false });
      console.log("useEFFECT finally : ");
      console.log(state);
    }
  }, []);

  return { ...state, triggerRefectch };
};
  • ๋‹ˆ์ฝ”์Œค ์ฝ”๋“œ
const useAxios = (opts, axiosInstance = defaultAxios) => {
  const [state, setState] = useState({
    loading: true,
    erorr: false,
    data: null,
  });
  const [trigger, setTrigger] = useState(false);

  const triggerRefectch = () => {
    setTrigger(!trigger);
    setState({ ...state, loading: true });
  };

  useEffect(async () => {
    axiosInstance(opts)
      .then((data) => {
        setState({
          ...state,
          loading: false,
          data,
        });
      })
      .catch((error) => {
        setState({ ...state, loading: false, error });
      });
  }, []);

  return { ...state, triggerRefectch };
};

2.10 Publishing to NPM

  • try React Helmet component like ~~

2.11 What to Learn Next

------------------------------------------------------------------------------------------

9.1 Context and State Management (8:59)

  • ์œ ์ €์˜ ํ”„๋กœํ•„,์ด๋ฉ”์ผ ์ •๋ณด๊ฐ€ ํ•„์š”ํ•ด, ๋ฉ”์ธํ™”๋ฉด,์ƒ์„ธํ™”๋ฉด ๋“ฑ > ๋งค๋ฒˆ API์„ ํ˜ธ์ถœํ• ์ˆ˜๋Š” ์—†๋‹ค.

  • ์—„์ฒญํฐ ์ปดํฌ๋„ŒํŠธ(๋ชจ๋‘๋ฅผ ๊ฐ์‹ธ๋Š”)๋ฅผ ๋งŒ๋“ค๊ณ , ํ•˜์œ„ ๋ผ์šฐํŒ…์„ ๋งŒ๋“ ๋‹ค. ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ๋งŒ ํ•˜๋ฉด ์ƒ๊ด€์—†๋‹ค.

  • ํ•˜์ง€๋งŒ, ์ •๋ณด๋ฅผ ์ˆ˜์ •ํ•œ๋‹ค๋ฉด, ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ๋Š” ์ ์ ์ปค์ง€๊ณ , Redux์˜ ํ•„์š”์„ฑ์ด ์ƒ๊ธด๋‹ค.

  • ๋งŒ์•ฝ, ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋งŽ์•„์ง„๋‹ค๊ณ  ์ƒ๊ฐํ•ด๋ด๋ผ. ํ—ค๋”์— ์œ ์ €์˜ ์ •๋ณด๊ฐ€ ์žˆ๋‹ค๋ฉด >

  • ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๋Š” ์ปดํฌ๋„ŒํŠธ > ํ—ค๋” ์ปดํฌ๋„ŒํŠธ > ์œ ์ € ์ •๋ณด ์ปดํฌ๋„ŒํŠธ ... : ๋“ฑ์˜ ์ˆœ์„œ๋กœ ์˜จ๋‹ค๋ฉด

  • ์œ ์ € ์ •๋ณด ์ปดํฌ๋„ŒํŠธ๋กœ props๋ฅผ ๋ณด๋‚ด๊ธฐ์œ„ํ•ด ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์“ฐ์ง€๋„ ์•Š์„ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š”๊ฑด ๋‚ญ๋น„๋‹ค.

  • ๋ฐ์ดํ„ฐ ํ•˜์šฐ์Šค๋ฅผ ํ•˜๋‚˜ ๋งŒ๋“ค์–ด์„œ, ์œ ์ € ์ด๋ฉ”์ผ, ์œ ์ € ํ”„๋กœํ•„์„ ์ €์žฅํ•ด๋†”

  • ํŠน์ • ์ปดํฌ๋„ŒํŠธ๊ฐ€ ํ•ด๋‹น ๋ฐ์ดํ„ฐ๊ฐ€ ํ•„์š”ํ• ๋–„๋งˆ๋‹ค ๊ฐ€์ ธ์˜ค๋ฉด ํ•ด๊ฒฐ๋˜์ง€.

  • ์ด๋Ÿฐ ์ €์žฅ์†Œ๋Š” ๋ฆฌ๋•์Šค,๋ชธ์—‘์Šค,UseContext ๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค. ( ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์žˆ์–ด.)

  • UseContext๋Š” ๋ณด๋‹ค ์‹ฌํ”Œํ•œ ์ƒํƒœ๊ด€๋ฆฌ์—์„œ ํŒŒ์›Œํ’€ ํ•˜๊ณ 

  • Redux๋Š” ์ข€ ๋” ์ปค๋‹ค๋ž€ Statesใ„น์™€ ๋งŽ์€ ๋ณ€ํ™”๋“ค์ด ์žˆ์„๋•Œ ์ ํ•ฉํ•˜๋‹ค๊ณ  ๋ณธ๋‹ค.

9.2 useContext in Action (12:33)

import React, { useState } from "react";

//์—ฌ๋Ÿฌ๊ตฐ๋Œ€์—์„œ ์‚ฌ์šฉ์˜ˆ์ •
//const { user, logUserIn, logUserOut } = useContext(UserContext); ์ด๋ ‡๊ฒŒ
export const UserContext = React.createContext();

const UserContextProvider = ({ children }) => {
  const [user, setUser] = useState({ name: "Dosimpact", loggedIn: false });
  const logUserIn = () => setUser({ ...user, loggedIn: true });
  const logUserOut = () => setUser({ ...user, loggedIn: false });
  return (
    <UserContext.Provider value={{ user, logUserIn, logUserOut }}>
      {children}
    </UserContext.Provider>
  );
};

//ํ•œ๋ฒˆ๋งŒ ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ ์„ ์–ธ ๋  ์˜ˆ์ •
export default UserContextProvider;
const Hook18 = () => {
  return (
    <UserContextProvider>
      <Screen />
    </UserContextProvider>
  );
};

const Screen = () => {
  return <Header />;
};

const Header = () => {
  const { user, logUserIn, logUserOut } = useContext(UserContext);
  return (
    <>
      <div>Hello {user.name}</div>
      <button onClick={logUserIn}>Login</button>
      <button onClick={logUserOut}>LogOut</button>
      <div>You are in {user.loggedIn ? "Log in " : "Log Out"}</div>
    </>
  );
};

9.3 Recap and Improvements (7:06)

import React, { useState, useContext } from "react";

//์—ฌ๋Ÿฌ๊ตฐ๋Œ€์—์„œ ์‚ฌ์šฉ์˜ˆ์ •
//const { user, logUserIn, logUserOut } = useContext(UserContext); ์ด๋ ‡๊ฒŒ
export const UserContext = React.createContext();

const UserContextProvider = ({ children }) => {
  const [user, setUser] = useState({ name: "Dosimpact", loggedIn: false });
  const logUserIn = () => setUser({ ...user, loggedIn: true });
  const logUserOut = () => setUser({ ...user, loggedIn: false });
  return (
    <UserContext.Provider value={{ user, Fns: { logUserIn, logUserOut } }}>
      {children}
    </UserContext.Provider>
  );
};

export const useUser = () => {
  const { user } = useContext(UserContext);
  return user;
};

export const useUserFns = () => {
  const { Fns } = useContext(UserContext);
  return Fns;
};

//ํ•œ๋ฒˆ๋งŒ ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ ์„ ์–ธ ๋  ์˜ˆ์ •
export default UserContextProvider;
import UserContextProvider, {
  UserContext,
  useUser,
  useUserFns,
} from "./context";

const Hook18 = () => {
  return (
    <UserContextProvider>
      <Screen />
    </UserContextProvider>
  );
};

const Screen = () => {
  return <Header />;
};

const Header = () => {
  // const { user, logUserIn, logUserOut } = useContext(UserContext);
  const userData = useUser();
  const userFns = useUserFns();
  return (
    <>
      <div>Hello {userData.name}</div>
      <button onClick={userFns.logUserIn}>Login</button>
      <button onClick={userFns.logUserOut}>LogOut</button>
      <div>You are in {userData.loggedIn ? "Log in " : "Log Out"}</div>
    </>
  );
};

9.4 Building Hypertranslate part One (10:13)

9.5 Building Hypertranslate part Two (5:40)

9.6 Understanding useReducer (8:55)

9.7 Reducer Recap (6:59)

9.8 Adding To Dos (8:27)

9.9 Deleting To Dos (7:37)

9.10 Completing To Dos (9:23)

9.11 Uncompleting To Dos (4:33)

9.12 Refactoring with Context (9:28)

9.13 Refactoring with Context part Two (10:35)

9.14 Conclusions (1:28)

๋ฆฌ์•กํŠธ ํ›… ์ฑŒ๋ฆฐ์ง€ - GeoLocation

  • ๋ฌธ์ œ ์ˆœ์ˆ˜ JS ๋กœ์ง์œผ๋กœ๋งŒ ๊ฐ„๋‹ค๋ฉด ๋ฆฌ๋žœ๋”๋ง์ด ์—†๋‹ค. ( ์‹ค์ œ๋ก  ์œ„์น˜์ •๋ณด ์ž˜ ๋ฐ›์•„์™”์ง€๋งŒ, ํ™”๋ฉด์— ๊ทธ๋ฆฌ์งˆ ๋ชปํ•จ.)
import { useState, useEffect } from "react";

export default () => {
  let state = { coords: { lat: null, long: null }, error: null };
  const succ = (pos) => {
    const { latitude: lat, longitude: long } = pos.coords;
    console.log(pos.coords);
    state = { ...state, coords: { lat, long } };
  };
  const error = (err) => {
    state = { ...state, error: true };
  };
  navigator.geolocation.getCurrentPosition(succ, error);
  return state;
};
  • ์ผ๋”ด state๋ฅผ ํ†ตํ•ด, ๋งŒ๋“ค์—ˆ๋‹ค. DOM ์ด ๋ฐ”๋€๋ถ€๋ถ„๋งŒ ๋žœ๋”๋ง ํ•œ๋‹ค ํ–ˆ์œผ๋‹ˆ, ํ˜„์žฌ ์œ„์น˜๊ฐ€ ๊ณ ์ •๋œ ์ด์ƒ, ๋ฌดํ•œ ๋žœ๋”๋ง์ด ๋ ๊นŒ? ( ์‹ค์ œ > ๋ฌดํ•œ ๋žœ๋”๋ง ์ค‘ ...)
import { useState } from "react";

export default () => {
  //const [updated, setUpdated] = useState(false);
  const [state, setState] = useState({
    coords: { lat: null, long: null },
    error: null,
  });

  const succ = (pos) => {
    const { latitude: lat, longitude: long } = pos.coords;
    setState({ ...state, coords: { lat, long } });
  };
  const error = (err) => {
    setState({ ...state, error: true });
  };
  const fetchData = () => {
    navigator.geolocation.getCurrentPosition(succ, error);
  };
  fetchData();
  return state;
};
  • useEffect๋ฅผ ์‚ฌ์šฉํ•ด์„œ, ๋ฌดํ•œ ๋žœ๋”๋ง์€ ๋ง‰์•˜์ง€๋งŒ, Effect ํ•œํ…Œ ๊ฑฐ์ง“๋ง์„ ํ–ˆ์Œ.
  • fetchDtatํ•จ์ˆ˜๋Š” ๋งค ๋žœ๋”๋ง ๋งˆ๋‹ค ๋ฐ”๋€Œ๋Š”๋ฐ, ์•ˆ๋ฐ”๋€๋‹ค๊ณ  ์–˜๊ธฐํ•จ.
import { useState, useEffect } from "react";

export default () => {
  //const [updated, setUpdated] = useState(false);
  const [state, setState] = useState({
    coords: { lat: null, long: null },
    error: null,
  });

  const succ = (pos) => {
    const { latitude: lat, longitude: long } = pos.coords;
    setState({ ...state, coords: { lat, long } });
  };
  const error = (err) => {
    setState({ ...state, error: true });
  };
  const fetchData = () => {
    navigator.geolocation.getCurrentPosition(succ, error);
  };
  //fetchData();
  useEffect(() => {
    fetchData();
  }, []);
  return state;
};
  • ์˜์กด์„ฑ ์™„์ „ ์ œ๊ฑฐ
import { useState, useEffect } from "react";

export default () => {
  const [state, setState] = useState({
    coords: { lat: null, long: null },
    error: null,
  });

  useEffect(() => {
    const succ = (pos) => {
      const { latitude: lat, longitude: long } = pos.coords;
      setState((pre) => ({ ...pre, coords: { lat, long } }));
    };
    const error = (err) => {
      setState((pre) => ({ ...pre, error: true }));
    };
    navigator.geolocation.getCurrentPosition(succ, error);
  }, []);
  return state;
};
  • ์นด์šดํ„ฐ
//๋งˆ๋ฒ•์˜ useEffect๊ฐ€ ์•ˆ๋๋‚˜๋Š” ํ˜„์ƒ...
const Counter = () => {
  const [cnt, setCnt] = useState(0);
  useEffect(() => {
    console.log("Effect is running");
    const id = setInterval(() => {
      setCnt((c) => {
        console.log("COUTER UPDATE", c);
        return c + 1;
      });
    }, 1000);
    return () => {
      console.log("EFFECT IS CLEARED");
      clearInterval(id);
    };
  }, []);
  return <>{cnt}</>;
};

const Couter02 = () => {
  const [cnt, setCnt] = useState(0);
  useEffect(() => {
    console.log("Effect is running");
    const id = setInterval(() => {
      console.log("COUTER UPDATE", cnt);
      setCnt(cnt + 1);
    }, 1000);
    return () => {
      console.log("EFFECT IS CLEARED");
      clearInterval(id);
    };
  }, [cnt]);

  return <>{cnt}</>;
};

const Couter03 = () => {
  const [cnt, setCnt] = useState(0);
  const [step, setStep] = useState(1);

  useEffect(() => {
    console.log("use Effect start");
    const id = setInterval(() => {
      setCnt((c) => {
        console.log("COUTER UPDATE", c);
        return c + step;
      });
    }, 1000);
    return () => {
      clearInterval(id);
      console.log("use Effect cleanUp");
    };
  }, [step]);

  return (
    <>
      <div>{cnt}</div>
      <input value={step} onChange={(e) => setStep(Number(e.target.value))} />
    </>
  );
};
  • ์ด๋ ‡๊ฒŒ ๋งŒ๋“ค์—ˆ๋”๋‹ˆ, map ์•ˆ์˜ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๋ฅผ ์žฌ ๋žœ๋”๋ง ํ•˜๋”๋ผ.
function App() {
  const titles = [
    { title: "useDeviceOrientation", JSXElemnet: Hook01 },
    { title: "useFavicon", JSXElemnet: Hook02 },
    { title: "useGeolocation", JSXElemnet: Hook03 },
    { title: "useKeyPress", JSXElemnet: Hook04 },
    { title: "useLocalStorage", JSXElemnet: Hook05 },
    { title: "useMousePosition", JSXElemnet: Hook06 },
    { title: "useOnline", JSXElemnet: Hook07 },
  ];
  return (
    <div className="App">
      <h1>Super Hooks !</h1>
      {titles.map((e, i) => (
        <Section title={e.title}>{e.JSXElemnet()}</Section>
      ))}
    </div>
  );
}
  • useEffect ๋ž‘ ๋ฐ”๋‹๋ผ๋ณ€์ˆ˜๋ฅผ ์“ด๋‹ค๋ฉด??? , ๋ณ€์ˆ˜๋ฅผ ์ „ํ˜€ ๋ฐ”๊ฟ€ ์ˆ˜ ์—†๋‹ค.
import { useState, useEffect } from "react";

export default () => {
  let pos = { x: 0, y: 0 };
  const [state, setState] = useState({ x: 0, y: 0 });
  const [lock, setLock] = useState(false);

  const lockScroll = () => {
    console.log("lock");
    setLock(true);
  };
  const unlockScroll = () => {
    setLock(false);
  };

  useEffect(() => {
    const handleChange = (e) => {
      if (lock) {
        console.log(`is Lock ${lock}`);
        window.scrollTo(pos.x, pos.y);
      } else {
        pos = { x: window.scrollX, y: window.scrollY };
        console.log(`scrolled ${pos.x} ,${pos.y}`);
      }
    };
    window.addEventListener("scroll", handleChange);
    return () => {
      window.removeEventListener("scroll", handleChange);
    };
  }, [lock]);

  return [lock, { lockScroll, unlockScroll }];
};

๋ฆฌ์•กํŠธ ํ›… ์ฑŒ๋ฆฐ์ง€ ์ •๋ฆฌ

import React from "react";
import ReactDOM from "react-dom";

import "./styles.css";

import {
  useDeviceOrientation,
  useFavicon,
  useGeolocation,
  useKeyPress,
  useLocalStorage,
  useMousePosition,
  useOnline,
  useLockScroll,
} from "./hooks";

const Section = ({ title, children }) => {
  return (
    <>
      <div>{title}</div>
      {children}
    </>
  );
};

function App() {
  // const titles = [
  //   { title: "useDeviceOrientation", JSXElemnet: Hook01 },
  //   { title: "useFavicon", JSXElemnet: Hook02 },
  //   { title: "useGeolocation", JSXElemnet: Hook03 },
  //   { title: "useKeyPress", JSXElemnet: Hook04 },
  //   { title: "useLocalStorage", JSXElemnet: Hook05 },
  //   { title: "useMousePosition", JSXElemnet: Hook06 },
  //   { title: "useOnline", JSXElemnet: Hook },
  // ];
  return (
    <div className="App">
      {/* <h1>Super Hooks !</h1>
      {titles.map((e, i) => (
        <Section title={e.title}>{e.JSXElemnet()}</Section>
      ))} */}

      <Section title={"useDeviceOrientation"}>
        <Hook01 />
      </Section>
      <Section title={"useFavicon"}>{Hook02()}</Section>
      <Section title={"useGeolocation"}>
        <Hook03 />
      </Section>
      <Section title={"useKeyPress"}>
        <Hook04 />
      </Section>
      <Section title={"useKeyPress"}>
        <Hook05 />
      </Section>
      <Section title={"useMousePosition"}>
        <Hook06 />
      </Section>
      <Section title={"useOnline"}>
        <Hook07 />
      </Section>
      <Section title={"useLockScroll"}>
        <Hook08 />
      </Section>
    </div>
  );
}

const Hook01 = () => {
  const { alpha, beta, gamma } = useDeviceOrientation();
  return (
    <ul>
      <li>alpha: {alpha}</li>
      <li>beta: {beta}</li>
      <li>gamma: {gamma}</li>
    </ul>
  );
};

const Hook02 = () => {
  const setFavicon = useFavicon("https://www.google.com/favicon.ico");

  return (
    <>
      <button onClick={() => setFavicon("https://facebook.com/favicon.ico")}>
        change favicon
      </button>
    </>
  );
};

const Hook03 = () => {
  const {
    coords: { lat, long },
    error,
  } = useGeolocation();
  // console.log(lat, long);
  return (
    <ul>
      <li>Latitude: {lat}</li>
      <li>Longitude: {long}</li>
      <li>GeoLocation error: {error === null ? "null" : "error"}</li>
    </ul>
  );
};

const Hook04 = () => {
  const kPressed = useKeyPress("k");
  const iPressed = useKeyPress("i");
  const mPressed = useKeyPress("m");
  const cPressed = useKeyPress("c");
  const hPressed = useKeyPress("h");
  return (
    <ul>
      <li>kPressed: {kPressed && "k"}</li>
      <li>iPressed: {iPressed && "i"}</li>
      <li>mPressed: {mPressed && "m"}</li>
      <li>cPressed: {cPressed && "c"}</li>
      <li>hPressed: {hPressed && "h"}</li>
      <li>iPressed: {iPressed && "i"}</li>
    </ul>
  );
};

const Hook05 = () => {
  const [currentLS, setLS] = useLocalStorage("JWT", "1234");

  return (
    <>
      <ul>
        <li>
          <div>Current Value: {currentLS}</div>
          <div>
            <button onClick={() => setLS("1234")}>Set value: 1234</button>
            <button onClick={() => setLS(null)}>Clear LS</button>
          </div>
        </li>
      </ul>
    </>
  );
};

const Hook06 = () => {
  const { x, y } = useMousePosition();
  return (
    <>
      <ul>
        <li>Mouse X: {x}</li>
        <li>Mouse Y: {y}</li>
      </ul>
    </>
  );
};

const Hook07 = () => {
  const isOnline = useOnline();
  return (
    <>
      <div>Are we online ? {isOnline ? "YES" : "NO"}</div>
    </>
  );
};
const Hook08 = () => {
  const [isLocked, { lockScroll, unlockScroll }] = useLockScroll();
  return (
    <>
      <div>is Locked ? {isLocked ? "YES" : "NO"}</div>
      <button onClick={() => lockScroll()}>lockScroll</button>
      <button onClick={() => unlockScroll()}>unlockScroll</button>
    </>
  );
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
export { default as useDeviceOrientation } from "./useDeviceOrientation";
export { default as useFavicon } from "./useFavicon";
export { default as useGeolocation } from "./useGeolocation";
export { default as useKeyPress } from "./useKeyPress";
export { default as useLocalStorage } from "./useLocalStorage";
export { default as useMousePosition } from "./useMousePosition";
export { default as useOnline } from "./useOnline";
export { default as useLockScroll } from "./useLockScroll";
  • useDeviceOrientation
import { useState, useEffect } from "react";

export default () => {
  const [state, setState] = useState({ alpha: null, beta: null, gamma: null });

  useEffect(() => {
    const handleOri = (e) => {
      setState({
        alpha: e.alpha,
        beta: e.beta,
        gamma: e.gamma,
      });
    };
    window.addEventListener("deviceorientation", handleOri, true);
    return () => {
      window.removeEventListener("deviceorientation", handleOri, true);
    };
  }, []);

  return { ...state };
};
  • useFavicon
export default (url) => {
  const setFavicon = (url) => {
    const El = document.querySelector("link#favicon");
    if (El && El.href) {
      El.href = url;
    }
  };
  setFavicon(url);
  return setFavicon;
};
  • useFavicon - nico
import { useEffect } from "react";

export function useFavicon(initialFavicon) {
  const setFavicon = (href) => {
    const link =
      document.querySelector("link[rel*='icon']") ||
      document.createElement("link");
    link.rel = "shortcut icon";
    link.href = href;
    const [head] = document.getElementsByTagName("head");
    head.appendChild(link);
  };
  useEffect(() => {
    setFavicon(initialFavicon);
  }, [initialFavicon]);
  return setFavicon;
}
  • useGeolocation
import { useState, useEffect } from "react";

export default () => {
  const [state, setState] = useState({
    coords: { lat: null, long: null },
    error: null,
  });

  useEffect(() => {
    const succ = (pos) => {
      const { latitude: lat, longitude: long } = pos.coords;
      setState((pre) => ({ ...pre, coords: { lat, long } }));
    };
    const error = (err) => {
      setState((pre) => ({ ...pre, error: true }));
    };
    navigator.geolocation.getCurrentPosition(succ, error);
  }, []);
  return state;
};
  • useKeyPress
import { useState, useEffect } from "react";

export default (i) => {
  const [key, setKey] = useState(false);
  useEffect(() => {
    const keyDownHandler = (e) => {
      const keyName = e.key;
      if (keyName === i) {
        setKey(() => true);
      }
    };
    const keyUpHandler = (e) => {
      const keyName = e.key;
      if (keyName === i) {
        setKey(() => false);
      }
    };
    document.addEventListener("keydown", keyDownHandler, false);
    document.addEventListener("keyup", keyUpHandler, false);
    return () => {
      document.removeEventListener("keydown", keyDownHandler, false);
      document.removeEventListener("keyup", keyUpHandler, false);
    };
  }, [i]);
  return key;
};
  • useLocalStorage
import { useState } from "react";
//key ์ด๋ฆ„๊ณผ, ์ดˆ๊ธฐ๊ฐ’์„ ์ง€์ •ํ•ด ์ค€๋‹ค.
//๋ฐ˜ํ™˜์œผ๋กœ ํ˜„์žฌ key์— ๋Œ€์‘ํ•˜๋Š” value๊ฐ’์„ ์ฃผ๊ณ , ๋ณ€๊ฒฝํ• ์ˆ˜ ์žˆ๋Š” ํ•จ์ˆ˜ ์ œ๊ณต
export default (key, initalValue) => {
  const [value, setValue] = useState(initalValue);

  const setLS = (nValue) => {
    localStorage.setItem(key, nValue);
    setValue(nValue);
  };

  return [value, setLS];
};
  • useLocalStorage - nico
import { useState } from "react";

export function useLocalStorage(name, initialValue) {
  const [currentValue, changeValue] = useState(() => {
    try {
      const item = localStorage.getItem(name);
      return item ? JSON.parse(item) : initialValue;
    } catch (e) {
      return initialValue;
    }
  });

  const updateValue = (newValue) => {
    try {
      changeValue(newValue);
      localStorage.setItem(name, JSON.stringify(newValue));
    } catch (e) {
      console.log(e);
    }
  };
  return [currentValue, updateValue];
}
  • useMousePosition
import { useState, useEffect } from "react";

export default () => {
  const [state, setState] = useState({ x: 0, y: 0 });

  useEffect(() => {
    const mouseMoveH = (e) => {
      // console.log(`
      // Screen X/Y: ${e.screenX}, ${e.screenY}
      // Client X/Y: ${e.clientX}, ${e.clientY}`);
      if (e.clientX && e.clientY) {
        setState({ x: e.clientX, y: e.clientY });
      }
    };
    document.addEventListener("mousemove", mouseMoveH);
    return () => {
      console.log("EFFECT CLEARED");
      document.removeEventListener("mousemove", mouseMoveH);
    };
  }, []);

  return state;
};
  • useOnline
import { useState, useEffect } from "react";

export default () => {
  const [state, setState] = useState(navigator.onLine);

  useEffect(() => {
    const handleChange = () => {
      setState(navigator.onLine);
    };
    window.addEventListener("online", handleChange);
    window.addEventListener("offline", handleChange);
    return () => {
      window.removeEventListener("online", handleChange);
      window.removeEventListener("offline", handleChange);
    };
  }, []);

  return state;
};
  • useLockScroll
import { useState, useEffect } from "react";

export default () => {
  //let pos = { x: 0, y: 0 };
  const [state, setState] = useState({ x: 0, y: 0 });
  const [lock, setLock] = useState(false);

  const lockScroll = () => {
    console.log("lock");
    setLock(true);
  };
  const unlockScroll = () => {
    setLock(false);
  };

  useEffect(() => {
    const handleChange = (e) => {
      if (lock) {
        window.scrollTo(state.x, state.y);
      } else {
        setState({ x: window.scrollX, y: window.scrollY });
        //  console.log(`scrolled ${state.x} ,${state.y}`);
      }
    };
    window.addEventListener("scroll", handleChange);
    return () => {
      window.removeEventListener("scroll", handleChange);
    };
  }, [lock]);

  return [lock, { lockScroll, unlockScroll }];
};
  • useLockScroll -nico
import { useState } from "react";

export function useLockScroll() {
  const [initialScroll] = useState(document.body.style.overflow);
  const [isLocked, setIsLocked] = useState(false);
  const lockScroll = () => {
    document.body.style.overflow = "hidden";
    setIsLocked(true);
  };
  const unlockScroll = () => {
    document.body.style.overflow = initialScroll;
    setIsLocked(false);
  };
  return [isLocked, { lockScroll, unlockScroll }];
}