[TIL] Day65 #Custom Hooks #React.lazy() #React.Suspense

Beanxxยท2022๋…„ 7์›” 28์ผ
0

TIL

๋ชฉ๋ก ๋ณด๊ธฐ
65/120
post-thumbnail

2022.07.28(Thurs)

[TIL] Day65
[SEB FE] Day66

โ˜‘๏ธย Custom Hooks

: ๋ฐ˜๋ณต๋˜๋Š” ๋กœ์ง์„ ํ•จ์ˆ˜๋กœ ๋ฝ‘์•„๋‚ด์–ด ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅ!

  • ์ƒํƒœ๊ด€๋ฆฌ ๋กœ์ง ์žฌํ™œ์šฉ ๊ฐ€๋Šฅ
  • ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ๋ณด๋‹ค ์ ์€ ์–‘์˜ ์ฝ”๋“œ๋กœ ๋™์ผํ•œ ๋กœ์ง ๊ตฌํ˜„ ๊ฐ€๋Šฅ
  • ํ•จ์ˆ˜ํ˜•์œผ๋กœ ์ž‘์„ฑํ•˜๋ฏ€๋กœ ๋ณด๋‹ค ๋ช…๋ฃŒ!

๐Ÿ“ŽCustom Hooks ์ •์˜ ๊ทœ์น™

  • ํ•จ์ˆ˜ ์ด๋ฆ„ ์•ž์— use ๋ถ™์ด๊ธฐ
  • ํ”„๋กœ์ ํŠธ ๋‚ด์˜ hooks ํด๋”์— ์œ„์น˜ ์‹œํ‚ค๊ธฐ
  • ํ•จ์ˆ˜๋Š” ์กฐ๊ฑด๋ถ€ ํ•จ์ˆ˜๊ฐ€ โŒย โ‡’ returnํ•˜๋Š” ๊ฐ’์€ ์กฐ๊ฑด๋ถ€ โŒ

โœ‹ย Hook ๋‚ด๋ถ€์— useState์™€ ๊ฐ™์€ React ๋‚ด์žฅ Hook ์‚ฌ์šฉ ๊ฐ€๋Šฅ!
โœ‹ย ๊ฐ™์€ Custom Hook ์‚ฌ์šฉํ–ˆ๋”๋ผ๋„ ๊ฐ™์€ state๋ฅผ ๊ณต์œ ํ•˜๋Š”๊ฑด ์•„๋‹˜ (๋กœ์ง๋งŒ ๊ณต์œ !)

// Custom Hook Example1
// ์—ฌ๋Ÿฌ url์„ fetchํ•  ๋•Œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” useFetch Hook
const useFetch = (initialUrl: string) => {
  const [url, setUrl] = useState(initialUrl);
  const [value, setValue] = useState("");

  const fetchData = () => axios.get(url).then(({ data }) => setValue(data));

  useEffect(() => {
    fetchData();
  }, [url]);

  return [value];
};

export default useFetch;
// Custom Hook Example2
// ์—ฌ๋Ÿฌ input์˜ ์ƒํƒœ ๋ณ€๊ฒฝ์— ์‚ฌ์šฉ๋˜๋Š” useInputs Hooks
import { useState, useCallback } from "react";

function useInputs(initialForm) {
  const [form, setForm] = useState(initialForm);

  const onChange = useCallback((e) => {
    const { name, value } = e.target;
    setForm((form) => ({ ...form, [name]: value }));
  }, []);

  const reset = useCallback(() => setForm(initialForm), [initialForm]);
  return [form, onChange, reset];
}

export default useInputs;


โ˜‘๏ธย ์ฝ”๋“œ ๋ถ„ํ•  (Code Spliting)

: ๋Ÿฐํƒ€์ž„์‹œ ์—ฌ๋Ÿฌ ๋ฒˆ๋“ค์„ ๋™์ ์œผ๋กœ ๋งŒ๋“ค๊ณ  ๋ถˆ๋Ÿฌ์˜ค๋Š” ๊ฒƒ

๐Ÿ‘‰ย ์ง€๊ธˆ ๋‹น์žฅ ํ•„์š”ํ•œ ์ฝ”๋“œ๊ฐ€ ์•„๋‹ˆ๋ฉด ๋”ฐ๋กœ ๋ถ„๋ฆฌ์‹œํ‚ค๊ณ , ๋‚˜์ค‘์— ํ•„์š”ํ•  ๋•Œ ๋ถˆ๋Ÿฌ์™€์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
โ‡’ ํŽ˜์ด์ง€ ๋กœ๋”ฉ ์†๋„ ๊ฐœ์„ !

๐Ÿค”ย ์–ด๋Š ํŽ˜์ด์ง€์—์„œ ์ฝ”๋“œ ์‹คํ–‰์ด ๋Š๋ ค์กŒ๋Š”์ง€ ํŒŒ์•…ํ•ด์„œ ๋ฒˆ๋“ค์„ ๋‚˜๋ˆˆ ๋’ค ์ง€๊ธˆ ํ•„์š”ํ•œ ์ฝ”๋“œ๋งŒ ๋ถˆ๋Ÿฌ์˜ค๋ฉด ์–ด๋–จ๊นŒ๋‚˜?
๐Ÿ‘‰ย ๋ฒˆ๋“ค์ด ๊ฑฐ๋Œ€ํ•ด์ง€๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•œ Good ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•: ๋ฒˆ๋“ค์„ ๋ฌผ๋ฆฌ์ ์œผ๋กœ ๋‚˜๋ˆ„๋Š” ๊ฒƒ !!


โœจย Third Party ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

: ๊ฐœ์ธ ๊ฐœ๋ฐœ์ž / ํ”„๋กœ์ ํŠธ ํŒ€ / ์—…์ฒด ๋“ฑ์—์„œ ๊ฐœ๋ฐœํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ, ์ œ3์ž ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
๐Ÿ‘Žย ๋‹ค์–‘ํ•œ ๋ฉ”์†Œ๋“œ ์ œ๊ณต โ†’ ์ฝ”๋“œ ์–‘ โฌ†๏ธ, ๋ฒˆ๋“ค๋ฆฌ์‹œ ๋งŽ์€ ๊ณต๊ฐ„ ์ฐจ์ง€

// loash: ๋ฐฐ์—ด, ์ˆซ์ž, ๊ฐ์ฒด, ๋ฌธ์ž์—ด ์‚ฌ์šฉ์‹œ ๋ฐ˜๋ณต ์ž‘์—…์„ ํ•  ๋•Œ ์‚ฌ์šฉํ•˜๊ธฐ ์ข‹์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

// loash ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ „์ฒด๋ฅผ ๋ถˆ๋Ÿฌ์™€์„œ ์‚ฌ์šฉ -> ๋น„ํšจ์œจ์ !
import _ from 'lodash';

_.find([]);

// loash ๋ฉ”์†Œ๋“œ ์ค‘ ํ•˜๋‚˜๋งŒ ๋ถˆ๋Ÿฌ์™€์„œ ์‚ฌ์šฉ -> ์•ฑ ์„ฑ๋Šฅ์— ๋” good!
import find from 'lodash/find';

find([]);

๐Ÿ“Žย Dynamic Import

: ๊ตฌ๋ฌธ ๋ถ„์„ / ์ปดํŒŒ์ผํ•ด์•ผ ํ•˜๋Š” ์Šคํฌ๋ฆฝํŠธ ์–‘ ์ตœ์†Œํ™”๋ฅผ ์œ„ํ•ด ์ง€์›

  • then()๋ฅผ ์‚ฌ์šฉํ•ด ํ•„์š”ํ•œ ์ฝ”๋“œ๋งŒ ๊ฐ€์ ธ์˜ด
  • ๊ฐ€์ ธ์˜จ ์ฝ”๋“œ์— ๋Œ€ํ•œ ๋ชจ๋“  ํ˜ธ์ถœ์€ ํ•ด๋‹น ํ•จ์ˆ˜ ๋‚ด๋ถ€์— ์žˆ์–ด์•ผ ํ•จ
// Dynamic Import Example

form.addEventListener('submit', e => {
	e.preventDefault();
	import('library.moduleA')
		.then(module => module.default)
		.then(someFunction())
		.catch(handleError());
	});

const someFunction = () => {
	// use moduleA here!!
}

โ†”๏ธย Static Import
: ์ฝ”๋“œ ํŒŒ์ผ ์ตœ์ƒ์œ„์— import๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉํ•˜๊ณ ์ž ํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ / ํŒŒ์ผ์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” ๋ฐฉ๋ฒ•

โœ‹ย React๋Š” SPA์ด๋ฏ€๋กœ ํ•œ๋ฒˆ์— ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ์ปดํฌ๋„ŒํŠธ๊นŒ์ง€ ๋ถˆ๋Ÿฌ์˜ค๋Š” ๋‹จ์  ์กด์žฌ



โ˜‘๏ธย React.lazy() & Suspense

๐Ÿ“Žย React.lazy()

: dynamic import๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ปดํฌ๋„ŒํŠธ ๋ Œ๋”๋ง ๊ฐ€๋Šฅ โ‡’ ์ดˆ๊ธฐ ๋ Œ๋”๋ง ์ง€์—ฐ ์‹œ๊ฐ„ ์–ด๋Š์ •๋„ ๋‹จ์ถ• ๊ฐ€๋Šฅ

import Component from './Component';

const Component = React.lazy(() => import('./Component'));

โœ‹ย React.lazy๋กœ ๊ฐ์‹ผ ์ปดํฌ๋„ŒํŠธ๋Š” ๋‹จ๋… ์‚ฌ์šฉ ๋ถˆ๊ฐ€ โ†’ React.suspense ์ปดํฌ๋„ŒํŠธ ํ•˜์œ„์—์„œ ๋ Œ๋”๋งํ•ด์•ผ ํ•จ

๐Ÿ“Žย React.Suspense

: ์•„์ง ๋ Œ๋”๋ง์ด ์ค€๋น„๋˜์ง€ ์•Š์€ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์žˆ์„ ๋•Œ ๋กœ๋”ฉ ํ™”๋ฉด์„ ๋ณด์—ฌ์ฃผ๊ณ ,
ย ย ๋กœ๋”ฉ ์™„๋ฃŒ์‹œ ๋ Œ๋”๋ง์ด ์ค€๋น„๋œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ณด์—ฌ์คŒ

import { Suspense } from "react";

const OtherComponent = React.lazy(() => import("./OtherComponent"));
const AnotherComponent = React.lazy(() => import("./AnotherComponent"));

function MyComponent() {
  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        <OtherComponent />
        <AnotherComponent />
      </Suspense>
    </div>
  );
}
  • fallback prop: ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋กœ๋“œ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋™์•ˆ ๋กœ๋”ฉ ํ™”๋ฉด์œผ๋กœ ๋ณด์—ฌ์ค„ Element๋ฅผ ๋ฐ›์•„๋“ค์ž„

โœ‹ย Suspense ์ปดํฌ๋„ŒํŠธ ํ•˜๋‚˜๋กœ ์—ฌ๋Ÿฌ ๊ฐœ lazy ์ปดํฌ๋„ŒํŠธ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ์Œ

โœจย React.lazy & Suspense๋ฅผ ํ†ตํ•œ ์ฝ”๋“œ ๋ถ„ํ• ์„ ์ค‘๊ฐ„์— ์ ์šฉ์‹œํ‚ค๋Š” ๊ฒƒ๋ณด๋‹ค Route์— ์ ์šฉ์‹œํ‚ค๋Š” ๊ฒƒ์ด ์ข‹์Œ!

// Router๊ฐ€ ๋ถ„๊ธฐ๋˜๋Š” ์ปดํฌ๋„ŒํŠธ์—์„œ React.lazy๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ import
// Route ์ปดํฌ๋„ŒํŠธ๋“ค์„ Suspense๋กœ ๊ฐ์‹ผ ํ›„, ๋กœ๋”ฉ ํ™”๋ฉด ์ปดํฌ๋„ŒํŠธ๋ฅผ fallback ์†์„ฑ์œผ๋กœ ์„ค์ •

import { Suspense, lazy } from "react";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";

const Home = lazy(() => import("./routes/Home"));
const About = lazy(() => import("./routes/About"));

const App = () => {
  <Router>
    <Suspense fallback={<div>Loading...</div>}>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
      </Routes>
    </Suspense>
  </Router>;
};

๐Ÿ‘ย ์ดˆ๊ธฐ ๋ Œ๋”๋ง ์‹œ๊ฐ„ โฌ‡๏ธ
๐Ÿ‘Žย ํŽ˜์ด์ง€ ์ด๋™ ๊ณผ์ •๋งˆ๋‹ค ๋กœ๋”ฉ ํ™”๋ฉด์ด ๋ณด์—ฌ์ง

profile
FE developer

0๊ฐœ์˜ ๋Œ“๊ธ€