๐Ÿ’ป๐Ÿ’€/๊ฐœ๋ฐœ

[React] resize ์ด๋ฒคํŠธ ๋‹ค๋ฃจ๊ธฐ

db2 2021. 8. 11. 09:44

+ 2022.07.13 ์ถ”๊ฐ€
๋Œ“๊ธ€์„ ๋ฌด์‹œํ• ๊นŒ ํ•˜๋‹ค๊ฐ€ ์•„๋ฌด๋ž˜๋„ ๋‚˜์˜ ์ž‘๊ณ  ๋‹ค ์“ฐ๋Ÿฌ์ ธ๊ฐ€๋Š” ๊ตฌ๋ฉ๊ฐ€๊ฒŒ ๊ฐ™์€ ๋ธ”๋กœ๊ทธ์— ์ด๋Ÿฐ ์˜๊ฒฌ์ด ๋“ค์–ด์˜ค๋Š” ์ผ์ด ๋˜ ์žˆ์„๊นŒ ์‹ถ์–ด ๋Šฆ๊ฒŒ๋ผ๋„ ํ”ผ๋“œ๋ฐฑ์„ ๋‚จ๊ฒจ๋ณธ๋‹ค.
๋จผ์ € ์ด ๊ธ€์€ ํ‹ฐ์Šคํ† ๋ฆฌ์— ๋“ฑ๋กํ•œ ์‹œ์ ๋ณด๋‹ค ํ›จ์”ฌ ์ด์ „์— ์“ด ๊ธ€์ด๋‹ค. ๊ทธ ๋‹น์‹œ ๊ตฌ๊ธ€๋ง์„ ํ†ตํ•ด์„œ ๋‚˜๋„ ์ฒ˜์Œ ์•Œ๊ฒŒ ๋œ ๋‚ด์šฉ์ด๊ณ , ๋„ˆ๋ฌด ์œ ์ตํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ณต์œ ํ•ด์•ผ๊ฒ ๋‹ค๋Š” ๋งˆ์Œ์œผ๋กœ ๊ธ€์„ ์“ฐ๊ธฐ ์‹œ์ž‘ํ–ˆ๋‹ค. ์‹œ๊ฐ„์ด ๊ฝค ์ง€๋‚ฌ์ง€๋งŒ ๋ถ„๋ช…ํžˆ ๊ธฐ์–ต๋‚˜๋Š” ๊ฑด ์™ธ๊ตญ ๊ธ€์„ ํ† ์”จํ•˜๋‚˜ ์•ˆ ํ‹€๋ฆฌ๊ณ  ๊ทธ๋Œ€๋กœ ๋ฒ ๊ปด ๋ฒˆ์—ญํ•œ ๊ฒŒ ์•„๋‹ˆ๋ผ ์ตœ๋Œ€ํ•œ ๋‚˜์˜ ์–ธ์–ด๋กœ ์ •๋ฆฌํ•˜๊ณ  ์†Œ์Šค๋„ ์ง์ ‘ ํ…Œ์ŠคํŠธ ํ•ด๋ณด๊ณ  ๋‚ด ๋ฐฉ์‹ ๋Œ€๋กœ ์ˆ˜์ •ํ–ˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค(์ด๊ฒŒ ๋” ๋‚˜์œ ๊ฑธ๊นŒ?ใ… ใ… ). ๊ทธ๋ž˜์„œ ์ด๋ฒˆ์— ํ˜น์‹œ๋‚˜ ์›๊ธ€์„ ์ฐพ์•„๋ดค๋Š”๋ฐ ์ •ํ™•ํžˆ ์ผ์น˜ํ•˜๋Š” ๊ธ€์„ ์ฐพ์ง€ ๋ชปํ–ˆ๋‹ค..๐Ÿ˜ฅ ํ•˜์ง€๋งŒ ์–ผ์ถ” ๊ฐ€์žฅ ๋น„์Šทํ•ด๋ณด์ด๊ณ  ๋‚˜๋„ ๋‚ฏ์ด ๊ฐ€์žฅ ์ต์€ ๊ธ€์„ ์ถœ์ฒ˜๋กœ ์ฒจ๋ถ€ํ–ˆ๋‹ค. (์ • ๋ฌธ์ œ๊ฐ€ ๋œ๋‹ค๋ฉด ๊ธ€์„ ๋‚ด๋ฆฌ๊ฒ ์Œ!) ์•ž์œผ๋กœ๋Š” ๊ฐ™์€ ์‹ค์ˆ˜๋ฅผ ๋ฐ˜๋ณตํ•˜์ง€ ์•Š๊ฒ ๋‹ค. ์ถœ์ฒ˜..์œ ์˜.. ๋ฉ”๋ชจ๋ฉ”๋ชจ...

๊ทธ๋ฆฌ๊ณ  ํ…์ŠคํŠธ ๋ณต์‚ฌ๋Š” ๊ณฐ๊ณฐํžˆ ์ƒ๊ฐํ•ด๋ณด๋‹ˆ ๋‚˜๋„ ๊ฐœ๋ฐœํ•˜๋ฉด์„œ ์ข…์ข… ๋‹ค๋ฅธ ๊ธ€์—์„œ ์˜ˆ์ œ ์†Œ์Šค๋ฅผ ๊ธ์–ด์™€ ํ™œ์šฉํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋“œ๋ž˜๊ทธ ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ’€์–ด๋’€๋‹ค๐Ÿ‘
(๋ถˆํŽธํ•จ์ด ์กฐ๊ธˆ์ด๋‚˜๋งˆ ํ•ด์†Œ๋๊ธธ ๋ฐ”๋ผ๋ฉฐ, ๋Œ“๊ธ€์€ ํฅ๋ฏธ์ง„์ง„ํ•˜๋‹ˆ๊นŒ ์‚ญ์ œํ•˜์ง€ ์•Š๋Š” ๊ฑธ๋กœ~)


โœจ Window Resize

๋ธŒ๋ผ์šฐ์ € ํ™”๋ฉด ์‚ฌ์ด์ฆˆ๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ, ๋ณ€๊ฒฝ๋œ ์‚ฌ์ด์ฆˆ ๊ฐ’์„ ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ์— ์ ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค. ๋ฐ”๋กœ window ๊ฐ์ฒด์— ๋ฐœ์ƒ๋˜๋Š” resize ์ด๋ฒคํŠธ๋ฅผ ๊ฐ์ง€ํ•˜๊ณ , ๊ทธ ๋•Œ๋งˆ๋‹ค ์ปดํฌ๋„ŒํŠธ์˜ state์— ์‚ฌ์ด์ฆˆ ๊ฐ’์„ ์ €์žฅํ•ด ๋ฆฌ๋ Œ๋”ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

1. ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ ์ฒ˜๋ฆฌ

useEffect์— ๋นˆ ๋ฐฐ์—ด์„ ์ „๋‹ฌํ•˜๋ฉด, ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ฒ˜์Œ ๋งˆ์šดํŠธ ๋  ๋•Œ์™€ ์–ธ๋งˆ์šดํŠธ ๋  ๋•Œ๋งŒ ์‹คํ–‰๋œ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋งˆ์šดํŠธ๋  ๋•Œ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋ฅผ ๋”ํ•˜๊ณ , ์–ธ๋งˆ์šดํŠธ ๋  ๋•Œ ์ œ๊ฑฐํ•ด์ค€๋‹ค.

โšก ์ค‘์š”

์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋ฅผ ์ œ๊ฑฐํ•˜์ง€ ์•Š์œผ๋ฉด, ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฆฌ๋ Œ๋”๋˜์–ด useEffect๊ฐ€ ์‹คํ–‰๋  ๋•Œ๋งˆ๋‹ค ์ƒˆ๋กœ์šด ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๊ฐ€ ํ•ธ๋“ค๋Ÿฌ์— ๋ฐ”์ธ๋”ฉ๋  ๊ฒƒ์ด๋‹ค. ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ž์ฃผ ๋ฆฌ๋ Œ๋”๋  ๊ฒฝ์šฐ์—๋Š”, ์ด๋กœ ์ธํ•ด ์‹ฌ๊ฐํ•œ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋ฆฌ๋ Œ๋”๋œ ํ›„, ์ƒˆ๋กœ์šด ๋ฆฌ์Šค๋„ˆ๊ฐ€ ์ƒ๊ธฐ๊ธฐ ์ด์ „์— ๊ธฐ์กด์˜ ๋ฆฌ์Šค๋„ˆ๋ฅผ ์ œ๊ฑฐํ•ด์ค˜์•ผ ํ•œ๋‹ค.

import React, { useEffect } from 'react';

const ResizedComponent = () => {
  const handleResize = () => {
    console.log(`๋ธŒ๋ผ์šฐ์ € ํ™”๋ฉด ์‚ฌ์ด์ฆˆ x: ${window.innerWidth}, y: ${window.innerHeight}`);
  }

  useEffect(() => {
    window.addEventListener('resize', handleResize);
    return () => { // cleanup 
      window.removeEventListener('resize', handleResize);
    }
  }, []);

  return <div>๋ธŒ๋ผ์šฐ์ € ํ™”๋ฉด ์‚ฌ์ด์ฆˆ x: {window.innerWidth}, y: {window.innerHeight}</div>
}

2. ์ปดํฌ๋„ŒํŠธ ๋ฆฌ๋ Œ๋”

๋ธŒ๋ผ์šฐ์ € ํ™”๋ฉด ์‚ฌ์ด์ฆˆ๋ฅผ ์ค„์ด๊ณ  ๋Š˜๋ฆด ๋•Œ๋งˆ๋‹ค ์ฝ˜์†”์— ๋ณ€๊ฒฝ๋˜๋Š” ์‚ฌ์ด์ฆˆ๊ฐ€ ์ž˜ ๋œฌ๋‹ค๋ฉด ์„ฑ๊ณต์ด๋‹ค! resize ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•  ๋•Œ๋งˆ๋‹ค handleResize ๋‚ด๋ถ€์˜ ์ฝ”๋“œ๊ฐ€ ์ž˜ ์‹คํ–‰๋˜๊ณ  ์žˆ๋‹ค๋Š” ๋œป์ด๋‹ค. ํ•˜์ง€๋งŒ ์•„๋ฌด๋ฆฌ handleResize ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜์–ด๋„ <div>์— ์ถœ๋ ฅ๋˜๋Š” ์‚ฌ์ด์ฆˆ๋Š” ๋ฐ”๋€Œ์ง€ ์•Š๋Š”๋‹ค. ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฆฌ๋ Œ๋” ๋˜์ง€ ์•Š๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๋ฆฌ์•กํŠธ์˜ ๊ธฐ๋ณธ์ ์ธ ์›๋ฆฌ(state๋‚˜ props๊ฐ€ ๋ณ€ํ•˜๋ฉด ์ปดํฌ๋„ŒํŠธ๋„ ๋ฆฌ๋ Œ๋” ๋˜๋Š” ์ )๋ฅผ ์ด์šฉํ•ด์„œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค. ํ™”๋ฉด ์‚ฌ์ด์ฆˆ๋ฅผ ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์˜ state๋กœ ๊ด€๋ฆฌํ•จ์œผ๋กœ์จ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ๋งˆ๋‹ค ์ปดํฌ๋„ŒํŠธํ•œํ…Œ "ํ™”๋ฉด ์‚ฌ์ด์ฆˆ ๋ฐ”๋€Œ์—ˆ์œผ๋‹ˆ๊นŒ ๋„ˆ๋„ ๋ฆฌ๋ Œ๋” ํ•ด!" ๋ผ๊ณ  ์•Œ๋ ค์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.

์•„๋ž˜์ฒ˜๋Ÿผ useState์„ ์‚ฌ์šฉํ•ด windowSize ๋ผ๋Š” state๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ , handleResize ์•ˆ์—์„œ state๊ฐ€ ์—…๋ฐ์ดํŠธ ๋˜๋„๋ก ํ•œ๋‹ค. ๊ทธ๋Ÿผ ํ™”๋ฉด ์‚ฌ์ด์ฆˆ๊ฐ€ ๋ฐ”๋€” ๋•Œ๋งˆ๋‹ค <div>์— ์ถœ๋ ฅ๋˜๋Š” ์‚ฌ์ด์ฆˆ๋„ ํ•จ๊ป˜ ๋ณ€๊ฒฝ๋  ๊ฒƒ์ด๋‹ค.

import React, { useEffect, useState } from 'react';

const ResizedComponent = () => {
  const [windowSize, setWindowSize] = useState({
    width: window.innerWidth,
    height: window.innerHeight
  });

  const handleResize = () => {
    setWindowSize({
      width: window.innerWidth,
      height: window.innerHeight
    });
  }

  useEffect(() => {
    window.addEventListener('resize', handleResize);
    return () => { // cleanup 
      window.removeEventListener('resize', handleResize);
    }
  }, []);

  return <div>๋ธŒ๋ผ์šฐ์ € ํ™”๋ฉด ์‚ฌ์ด์ฆˆ x: {window.width}, y: {window.height}</div>
}

3. ๋””๋ฐ”์šด์Šค(Debounce)

์šฐ๋ฆฌ๋Š” ์ด์ œ ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์—์„œ ๋ณ€๊ฒฝ๋˜๋Š” ๋ธŒ๋ผ์šฐ์ € ํ™”๋ฉด ์‚ฌ์ด์ฆˆ๋ฅผ ๊ฐ์ง€ํ•ด ์›ํ•˜๋Š” ์ž‘์—…์„ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋๋‹ค. ์—ฌ๊ธฐ์„œ ํ•œ ๊ฐ€์ง€, px ๋‹จ์œ„๋กœ ๋งค๋ฒˆ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ํ˜ธ์ถœ๋  ํ•„์š”๊ฐ€ ์žˆ์„ ์ง€๋ฅผ ๊ณ ๋ คํ•ด๋ณด๋ฉด ์ข‹๊ฒ ๋‹ค. ํ•„์š” ์ด์ƒ์œผ๋กœ ์žฆ์€ ๋ฆฌ๋ Œ๋”๋Š” ์„ฑ๋Šฅ์ƒ์œผ๋กœ๋„ ์ข‹์ง€ ์•Š์„ ๊ฒƒ์ด๋ฉฐ, ๊ฒฐ๊ตญ ๋‚ด๊ฐ€ ํ•„์š”ํ•œ ๊ฐ’์€ ๋งจ ๋งˆ์ง€๋ง‰์— ๊ฒฐ์ •๋œ ์‚ฌ์ด์ฆˆ ๊ฐ’ ํ•˜๋‚˜์ผํ…Œ๋‹ˆ๊นŒ. ์ด๋Ÿด ๋•Œ๋Š” debounce๋ผ๋Š” ๊ธฐ์ˆ ์„ ์ด์šฉํ•ด ๋ฆฌ๋ Œ๋”์˜ ํšŸ์ˆ˜๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค.

โ—ฝ ๋””๋ฐ”์šด์Šค(Debounce)๋ž€
์ด๋ฒคํŠธ๋ฅผ ๊ทธ๋ฃนํ™”ํ•ด ํŠน์ • ์‹œ๊ฐ„์ด ์ง€๋‚œ ํ›„, ํ•˜๋‚˜์˜ ์ด๋ฒคํŠธ๋งŒ ๋ฐœ์ƒํ•˜๋„๋ก ํ•˜๋Š” ๊ธฐ์ˆ ์ด๋‹ค. ์ฆ‰, ์—ฐ์ด์–ด ํ˜ธ์ถœ๋˜๋Š” ํ•จ์ˆ˜๋“ค ์ค‘ ๋งˆ์ง€๋ง‰ ํ˜น์€ ์ œ์ผ ์ฒ˜์Œ๋งŒ ํ˜ธ์ถœํ•˜๋„๋ก ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

์ž์„ธํ•œ ๋‚ด์šฉ์€ ์—ฌ๊ธฐ๋ฅผ ์ฐธ๊ณ ํ•˜๊ธธ ์ถ”์ฒœ...

lodash ํŒจํ‚ค์ง€๊ฐ€ ์ œ๊ณตํ•˜๋Š” debounce ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด, handleResize ํ•จ์ˆ˜๊ฐ€ 1์ดˆ๋งˆ๋‹ค ํ˜ธ์ถœ๋  ์ˆ˜ ์žˆ๋„๋ก ์ ์šฉํ•ด์ค€๋‹ค. (lodash ์„ค์น˜ ๋ถ€๋ถ„์€ ํŒจ์Šค๐Ÿ’จ). ๊ทธ๋Ÿผ ๋”์ด์ƒ px ๋‹จ์œ„๋กœ ๋ฆฌ๋ Œ๋” ๋˜์ง€ ์•Š๊ณ , 1์ดˆ๋งˆ๋‹ค ํ•œ ๋ฒˆ์”ฉ ๋ฆฌ๋ Œ๋”๊ฐ€ ๋  ๊ฒƒ์ด๋‹ค.

import React, { useEffect, useState } from 'react';
import { debounce } from 'lodash';

const ResizedComponent = () => {
  const [windowSize, setWindowSize] = useState({
    width: window.innerWidth,
    height: window.innerHeight
  });

  // handleResize ํ•จ์ˆ˜๋ฅผ debounce๋กœ ๊ฐ์‹ธ๊ณ , ์‹œ๊ฐ„์„ ์„ค์ •ํ•œ๋‹ค
  // 1000ms = 1sec
  const handleResize = debounce(() => {
    setWindowSize({
      width: window.innerWidth,
      height: window.innerHeight
    });
  }, 1000);

  useEffect(() => {
    window.addEventListener('resize', handleResize);
    return () => { // cleanup 
      window.removeEventListener('resize', handleResize);
    }
  }, []);

  return <div>๋ธŒ๋ผ์šฐ์ € ํ™”๋ฉด ์‚ฌ์ด์ฆˆ x: {window.width}, y: {window.height}</div>
}

์ถœ์ฒ˜์ผ์ง€๋„ ๋ชจ๋ฅด๋Š” ๊ธ€(๊ฐ€์žฅ ์œ ์‚ฌ): https://www.pluralsight.com/guides/re-render-react-component-on-window-resize