React ์ตœ์ ํ™” & ์„ฑ๋Šฅ๊ฐœ์„ ๐Ÿ’ก

๐ŸงกReact์˜ ๋ฆฌ๋ Œ๋”๋ง

  1. props๊ฐ€ ๋ณ€๊ฒฝ๋˜์—ˆ์„ ๋•Œ
  2. state๊ฐ€ ๋ณ€๊ฒฝ๋˜์—ˆ์„ ๋•Œ
  3. ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง ๋˜์—ˆ์„ ๋•Œ

๋ถ€๋ชจ์ปดํฌ๋„ŒํŠธ์˜ state๊ฐ€ ํ•˜๋‚˜๋งŒ ๋ณ€ํ•ด๋„ ํ•˜์œ„์ปดํฌ๋„ŒํŠธ ์ „์ฒด์˜ ๋ฆฌ๋ Œ๋”๋ง์ด ์ผ์–ด๋‚˜๊ธฐ ๋•Œ๋ฌธ์—
์ž˜๋ชป ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ”๋ชจ๋ฆฌ๋‚ญ๋น„๊ฐ€ ํฌ๊ฒŒ ๋ฐœ์ƒํ•˜๋ฉฐ ์„ฑ๋Šฅ์ด ๋–จ์–ด์งˆ ์ˆ˜ ์žˆ๋‹ค

React app์˜ ์„ฑ๋Šฅ ์ตœ์ ํ™”๋ฅผ ์œ„ํ•ด ๋ฆฌ๋ Œ๋”๋ง ๋˜๋Š” ๋ถ€๋ถ„์„ ์ตœ์†Œํ™”ํ•ด์•ผ ํ•จ

๐Ÿงก์ตœ์ ํ™” Hooks

โœจuseMemo()

useMemo(์‹คํ–‰ํ•  ํ•จ์ˆ˜, [๋ณ€ํ™”ํ•˜๋Š”์ง€ ์ง€์ผœ๋ณผ ๊ฐ’(Dependency)]);
  • ํ•จ์ˆ˜์˜ ๊ฒฐ๊ณผ๊ฐ’(return)์„ ์ €์žฅํ•˜์—ฌ ์‚ฌ์šฉ
  • ๋””ํŽœ๋˜์‹œ ๊ฐ’์ด ๋ณ€ํ™”ํ•˜์ง€ ์•Š์œผ๋ฉด ํ•จ์ˆ˜๋Š” ์žฌ์‹คํ–‰ ๋˜์ง€ ์•Š๊ณ , ์ €์žฅ๋œ ๊ฐ’์„ ์‚ฌ์šฉ
  • ๋ถˆํ•„์š”ํ•œ ์ƒํ™ฉ์— ํ•ด๋‹น ํ•จ์ˆ˜๊ฐ€ ์žฌํ˜ธ์ถœ ๋˜๋Š”๊ฒƒ์„ ๋ฐฉ์ง€

โœจuseCallback()

useCallback(์‹คํ–‰ํ•  ํ•จ์ˆ˜, [๋ณ€ํ™”ํ•˜๋Š”์ง€ ์ง€์ผœ๋ณผ ๊ฐ’(Dependency)])
  • ํ•จ์ˆ˜ ๊ทธ ์ž์ฒด๋ฅผ ์ €์žฅํ•˜์—ฌ ์žฌํ™œ์šฉ
  • ๋””ํŽœ๋˜์‹œ ๊ฐ’์ด ๋ณ€ํ™”ํ•˜์ง€ ์•Š์œผ๋ฉด ํ•จ์ˆ˜๋Š” ์žฌ์„ ์–ธ๋˜์ง€ ์•Š์Œ
  • ํ•ด๋‹น ํ•จ์ˆ˜๋ฅผ props๋กœ ๋ฐ›๋Š” ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์˜ ๋ฆฌ๋ Œ๋”๋ง์„ ๋ฐฉ์ง€

โœจReact.memo()

export default React.memo(์ปดํฌ๋„ŒํŠธ)
  • React.memo๋กœ ๊ฐ์‹ผ ์ปดํฌ๋„ŒํŠธ๋Š” ๋ถ€๋ชจ์ปดํฌ๋„ŒํŠธ๋กœ๋ถ€ํ„ฐ ์ „๋‹ฌ๋ฐ›๋Š” props์˜ ๊ฐ’์ด ๋ณ€ํ™”ํ•˜์ง€ ์•Š์œผ๋ฉด, ๋ถ€๋ชจ์ปดํฌ๋„ŒํŠธ์˜ ๋ฆฌ๋ Œ๋”๋ง์ด ์ผ์–ด๋‚˜๋„, ๋ฆฌ๋ Œ๋”๋ง ๋˜์ง€ ์•Š์Œ
  • props๋กœ ํ•จ์ˆ˜๋ฅผ ์ „๋‹ฌ๋ฐ›๋Š” ๊ฒฝ์šฐ ํ•ด๋‹น ํ•จ์ˆ˜์— useCallback์„ ํ•จ๊ป˜ ์‚ฌ์šฉํ•ด์ฃผ์–ด์•ผ ํšจ๊ณผ๊ฐ€ ์žˆ์Œ

โœจ์ฃผ์˜์ 

  • ๊ฐ ์ตœ์ ํ™” hook์˜ dependency๊ฐ’์œผ๋กœ ๋“ค์–ด๊ฐ€๋Š” ์š”์†Œ๊ฐ€ ๋งŽ์•„์งˆ์ˆ˜๋ก ์ตœ์ ํ™”๋Š” ์ง„ํ–‰ํ•˜๋Š” ์˜๋ฏธ๊ฐ€ ์—†์Œ.
  • ์ตœ์ ํ™” hook์„ ๋‚จ๋ฐœํ•˜๋Š” ๊ฒฝ์šฐ ์˜คํžˆ๋ ค ๋ฉ”๋ชจ๋ฆฌ ๋‚ญ๋น„๋กœ ์ด์–ด์งˆ ์ˆ˜ ์žˆ์Œ
  • dependency๊ฐ’์ด ๋น„์–ด์žˆ๋Š” hook์€ ์ ์ ˆํ•˜๋‚˜, ํ•˜๋‚˜ ์ด์ƒ์˜ dependency๊ฐ€ ๋“ค์–ด๊ฐ€๋Š” ๊ฒฝ์šฐ ์‚ฌ์šฉ์„ ํ•œ๋ฒˆ ๋” ๊ณ ๋ คํ•ด๋ณด์ž

dependency๋ฅผ ๋น„์šด useCallback() ์ž‘์„ฑ๋ฒ•

  1. dependency๋ฅผ ๋น„์šฐ์ง€ ์•Š์€ useCallback()
const [userInput, setUserInput] = useState('');

const onChange = useCallback(e => {
    const { name, value } = e.target;
    setUserInput({...userInput, [name]: value});
  },[userInput])
  1. dependency๋ฅผ ๋น„์šด useCallback()
const [userInput, setUserInput] = useState('');

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

(setterํ•จ์ˆ˜ ์‚ฌ์šฉ ์‹œ, ์ด์ „ state๋ฅผ ์ธ์ž๋กœ ๋ฐ›์•„์„œ ์‚ฌ์šฉ)

๐Ÿงก์ตœ์ ํ™” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

โœจlodash / debounce

  • $ yarn add lodash

  • inputํƒœ๊ทธ์˜ onChange ํ˜น์€ ์Šคํฌ๋กค ์ด๋ฒคํŠธ์™€ ๊ฐ™์ด ์งง์€ ์‹œ๊ฐ„์•ˆ์— ๋„ˆ๋ฌด ๋งŽ์€ ํ•จ์ˆ˜์˜ ์žฌํ˜ธ์ถœ์ด ์ผ์–ด๋‚˜๋Š” ๊ฒฝ์šฐ ์‚ฌ์šฉ

  • lodash์˜ debounce๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด, ์ง€์ •ํ•œ ํ•จ์ˆ˜์˜ ๋งˆ์ง€๋ง‰ ํ˜ธ์ถœ๋กœ๋ถ€ํ„ฐ ์ง€์ •ํ•œ ์‹œ๊ฐ„๋™์•ˆ ํ•จ์ˆ˜์˜ ์žฌํ˜ธ์ถœ์ด ์ผ์–ด๋‚˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ์—๋งŒ ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋œ๋‹ค

  debounce( ์‹คํ–‰ํ•  ํ•จ์ˆ˜ , 500 )
  • ์œ„์™€ ๊ฐ™์ด ์ž‘์„ฑํ•œ ๊ฒฝ์šฐ ๋งˆ์ง€๋ง‰ ํ•จ์ˆ˜ ํ˜ธ์ถœ๋กœ๋ถ€ํ„ฐ 500ms๋™์•ˆ ํ•จ์ˆ˜์˜ ์žฌํ˜ธ์ถœ์ด ์ผ์–ด๋‚˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ ํ•จ์ˆ˜ ์‹คํ–‰

โœจreact-window / FixedSizeList

  • $ yarn add react-window

  • ํ•œ ํ™”๋ฉด์— ๋„ˆ๋ฌด ๋งŽ์€ ์ปจํ…์ธ ๊ฐ€ ์—…๋กœ๋“œ๋˜์–ด์•ผ ํ•  ๋•Œ ์‚ฌ์šฉ

  • ์ง€์ •ํ•œ ํ™”๋ฉด์˜ ํฌ๊ธฐ์•ˆ์— ๋“ค์–ด์˜ค๋Š” ์–‘์˜ ์ปจํ…์ธ ๋งŒ ๋จผ์ € ๋ Œ๋”๋ง ๋˜๋„๋ก ํ•จ

  • ๋„˜์น˜๋Š” ๋ฐ์ดํ„ฐ๋Š” ์Šคํฌ๋กค์˜ ์œ„์น˜์— ๋”ฐ๋ผ ํ•„์š”ํ•  ๋•Œ ๋ Œ๋”

โœจ์‚ฌ์šฉ๋ฒ•

import React from 'react'
import { userData as users } from '../data/users'
import { FixedSizeList as List } from 'react-window'

function Users() {
  return (
    <List width={500} height={500} itemSize={50} itemCount={80}>
      {({index, style}) => 
        <div key={users[index].id} style={style} >
          {users[index].name}
        </div>
      }
      </List>
  )
}

export default Users
  1. import { FixedSizeList as List } from 'react-window' ๋กœ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ถˆ๋Ÿฌ์˜ด

  2. ์ปดํฌ๋„ŒํŠธ์— ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณด์—ฌ์งˆ ์ฐฝ์˜ ํฌ๊ธฐ๋ฅผ ์ง€์ •ํ•˜๋Š” width, height
    ๊ฐ ๋ฐ์ดํ„ฐ๊ฐ€ ์ฐจ์ง€ํ•  ๋†’์ดitemSize, ์•„์ดํ…œ์˜ ๊ฐฏ์ˆ˜ itemCount ๋ฅผ ์„ค์ •
    <List width={500} height={500} itemSize={50} itemCount={80}></List>

  3. ์ปดํฌ๋„ŒํŠธ ๋‚ด์— ํ•จ์ˆ˜๋ฅผ ๋„ฃ๊ณ  ํ•ด๋‹น ํ•จ์ˆ˜์˜ ์ธ์ž๋กœ index์™€style๋ฅผ ๊ฐ์ฒด๋ถ„ํ•ดํ• ๋‹น์œผ๋กœ ๋ฐ›์•„์˜ด

  4. ํ•จ์ˆ˜์•ˆ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•ด ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊พธ๋ฉฐ์ฃผ๋Š”๋ฐ, map()์„ ์‚ฌ์šฉํ•˜๋Š” ๋Œ€์‹  ์ธ์ž๋กœ ๋ฐ›์€ index๋ฅผ ํ™œ์šฉํ•œ๋‹ค

  5. ํ•จ์ˆ˜ ๋‚ด ์ตœ์ƒ๋‹จ ์š”์†Œ์— ์ธ์ž๋กœ ๋ฐ›์€ style์„ ์ ์šฉ์‹œ์ผœ์คŒ

โœจlazy loading

  • ๋ฆฌ์•กํŠธ๋Š” ์ดˆ๊ธฐ ๋กœ๋”ฉ๊ณผ์ •์—์„œ ์ „์ฒด ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ•œ๋ฒˆ์— ๋ถˆ๋Ÿฌ์˜ค๋Š”๋ฐ, ํŽ˜์ด์ง€ ์ „ํ™˜์ด ๋น ๋ฅด๋‹ค๋Š” ์žฅ์ ์ด ์žˆ์ง€๋งŒ ์ดˆ๊ธฐ ๋กœ๋”ฉ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆฐ๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ์Œ

  • lazy()๋Š” ํŠน์ •์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋‚˜์ค‘์— ๋ถˆ๋Ÿฌ์™€์ง€๋„๋ก ๋ถ„๋ฆฌ

๊ธฐ์กด ์ปดํฌ๋„ŒํŠธ import๋ฐฉ์‹

import UserList from './components/UserList';

function App() {
  return (
    <UserList />
  )
}

lazy ๋ฐฉ์‹

import { lazy, Suspense } from 'react';

const UserList = lazy(() => import('./components/UserList'))

function App() {
  return (
    <Suspense fallback={์ปดํฌ๋„ŒํŠธ}>
      <UserList />
    <Suspense>
  )
}

- ๋งŒ์•ฝ lazy์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋กœ๋“œ๋˜๊ธฐ ์ „์— ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ถˆ๋Ÿฌ์™€์•ผ ํ•  ๋•Œ, ๋กœ๋“œ๊ฐ€ ์™„๋ฃŒ ๋  ๋•Œ ๊นŒ์ง€ suspense์˜ fallback์•ˆ์˜ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋จผ์ € ๋ถˆ๋Ÿฌ์™€์„œ ๋ณด์—ฌ์ค€๋‹ค.
(fallback์•ˆ์— ๋กœ๋”ฉ์ด๋ฏธ์ง€๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ)

โœจlazyWithPreload

  • $ yarn add react-lazy-with-preload

  • ํŠน์ •ํ•œ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ, ์ง€์ •ํ•œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ถˆ๋Ÿฌ์˜ด

  • ์ปดํฌ๋„ŒํŠธ.preload()๋ฅผ ํ˜ธ์ถœํ–ˆ์„ ๋•Œ, ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ถˆ๋Ÿฌ์˜จ๋‹ค

import { lazyWithPreload } from "react-lazy-with-preload";

const UserList = lazyWithPreload(() => import('./components/UserList'))

function App() {
  const [isClicked, setIsClicked] = useState(false)

  return (
    <div>
      {isClicked && <UserList />}
      <button onMouseOver={() => UserList.preload()} onClick={() => setIsClicked(true)}
      >userlistํ‘œ์‹œ</button>
    </div>
  )
}
  • ๋ฒ„ํŠผ์— MouseOverํ–ˆ์„ ๋•Œ UserList์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๊ณ , Clickํ–ˆ์„ ๋•Œ ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ณด์—ฌ์ง€๋„๋ก ํ•จ

โœจredux์ตœ์ ํ™” / createSelector

  • ํ•œ ์ปดํฌ๋„ŒํŠธ ๋‚ด์—์„œ ํŠน์ • state๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ ๋งˆ๋‹ค, useSelect๋‚ด์˜ state๋ณ€๊ฒฝ์ด ์ „ํ˜€ ์—†์Œ์—๋„, ๋งค๋ฒˆ useSelect์˜ ๋ฆฌ๋ Œ๋”๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒ

  • createSelector๋Š” state๊ฐ’์„ ์ €์žฅํ•˜์—ฌ, ๊ฐ’์ด ๋ณ€ํ• ๋•Œ๋งŒ useSelector๊ฐ€ ๋ Œ๋”๋ง ๋˜๋„๋ก ํ•จ

// reducer.js
export const memoizedSelector = createSelector(
  state => state,
  value => value
)
  • useSelector์—์„œ memoized๋œ Selector๋ฅผ ๋ถˆ๋Ÿฌ์™€์„œ ์‚ฌ์šฉํ•˜๋ฉด ํ•ด๋‹น ํ˜„์ƒ์ด ํ•ด๊ฒฐ๋จ
  const count = useSelector(memoizedSelector);
profile
ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž ์„ฑ์žฅ์ผ๊ธฐ ๐Ÿ’ญ

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