๊ฐœ๋ฐœ ๊ณต๋ถ€/๋ฐ๋ธŒ์ฝ”์Šค TIL

[ํด๋ผ์šฐ๋”ฉ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ์—”์ง€๋‹ˆ์–ด๋ง TIL] 240207 - React ๊ธฐ๋ณธ. ๊ฐ„๋‹จํ•œ ์ผ๊ธฐ์žฅ ํ”„๋กœ์ ํŠธ 3

๊ฐ€์šค์ด 2024. 2. 8. 10:49

Intro


๋ฆฌ์•กํŠธ์—์„œ useMemo์™€ React.memo์— ๋Œ€ํ•ด ํ•™์Šตํ–ˆ๋‹ค.

๊ฐ•์˜๋Š” ๊ธธ์ง€ ์•Š์•˜์ง€๋งŒ ์กฐ๊ธˆ ํ—ท๊ฐˆ๋ฆฌ๊ธฐ ์‹œ์ž‘ํ–ˆ๋”ฐ.. ๊ผผ๊ผผํžˆ ๋ณต์Šต์„ ํ•ด์•ผ๊ฒ ๋‹ค.

 

 

 

์˜ค๋Š˜ ํ•™์Šตํ•œ ๋‚ด์šฉ

: API ํ˜ธ์ถœํ•˜๊ธฐ, Memoization(useMemo, React.memo)


React์—์„œ API ํ˜ธ์ถœํ•˜๊ธฐ

์„ธ๋ถ€ ๋ชฉํ‘œ

  • useEffect๋ฅผ ์ด์šฉํ•˜์—ฌ ์ปดํฌ๋„ŒํŠธ Mount ์‹œ์ ์— API๋ฅผ ํ˜ธ์ถœํ•˜๊ณ 
  • ํ•ด๋‹น API ๊ฒฐ๊ณผ๊ฐ’์„ ์ผ๊ธฐ ๋ฐ์ดํ„ฐ์˜ ์ดˆ๊ธฐ๊ฐ’์œผ๋กœ ์ด์šฉํ•˜๊ธฐ

JSONPlaceholder: APIํ˜ธ์ถœ ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด ์ƒ˜ํ”Œ ๋ฐ์ดํ„ฐ๋ฅผ ์ œ๊ณตํ•˜๋Š” REST API ์„œ๋น„์Šค

https://jsonplaceholder.typicode.com/

 

JSONPlaceholder - Free Fake REST API

{JSON} Placeholder Free fake API for testing and prototyping. Powered by JSON Server + LowDB. Tested with XV. Serving ~2 billion requests each month.

jsonplaceholder.typicode.com

 

API ํ˜ธ์ถœ ์˜ˆ์‹œ)

const getData = async () => {
  const res = await fetch('https://jsonplaceholder.typicode.com/comments').then((res) => res.json());
  console.log(res);
};

useEffect(() => {
  getData();
}, []);

: fetchํ•จ์ˆ˜๋กœ API๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  Mount ์‹œ์ ์— API๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ํ•จ์ˆ˜์ธ getData๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ ์œ„ํ•ด useEffect๋ฅผ ์ด์šฉํ•œ๋‹ค.

 

React Developer Tools: ๋ฆฌ์•กํŠธ ๊ฐœ๋ฐœํ•  ๋•Œ ์œ ์šฉํ•œ ํฌ๋กฌ ํ™•์žฅ ์•ฑ

https://chromewebstore.google.com/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi

 

React Developer Tools

Adds React debugging tools to the Chrome Developer Tools. Created from revision 993c4d003 on 12/5/2023.

chrome.google.com

 

 

 

์ตœ์ ํ™”1 - ์—ฐ์‚ฐ ๊ฒฐ๊ณผ ์žฌ์‚ฌ์šฉ (useMemo)

์„ธ๋ถ€ ๋ชฉํ‘œ

  • ํ˜„์žฌ ์ผ๊ธฐ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถ„์„ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ์ œ์ž‘ํ•˜๊ณ  ํ•ด๋‹น ํ•จ์ˆ˜๊ฐ€ ์ผ๊ธฐ ๋ฐ์ดํ„ฐ์˜ ๊ธธ์ด๊ฐ€ ๋ณ€ํ™”ํ•˜์ง€ ์•Š์„ ๋•Œ ๊ฐ’์„ ๋‹ค์‹œ ๊ณ„์‚ฐํ•˜์ง€ ์•Š๋„๋ก ํ•˜๊ธฐ
โœ… Memoization ์ดํ•ดํ•˜๊ธฐ!
: ์ด๋ฏธ ๊ณ„์‚ฐ ํ•ด ๋ณธ ์—ฐ์‚ฐ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ์–ต ํ•ด ๋‘์—ˆ๋‹ค๊ฐ€ ๋™์ผํ•œ ๊ณ„์‚ฐ์„ ์‹œํ‚ค๋ฉด, ๋‹ค์‹œ ์—ฐ์‚ฐํ•˜์ง€ ์•Š๊ณ  ๊ธฐ์–ต ํ•ด ๋‘์—ˆ๋˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ ์‹œํ‚ค๊ฒŒ ํ•˜๋Š” ๋ฐฉ๋ฒ•

 

// data.length๊ฐ€ ๋ณ€ํ™”ํ•  ๋•Œ๋งŒ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋จ
const getDiaryAnalysis = useMemo(() => {
  console.log('์ผ๊ธฐ ๋ถ„์„ ์‹œ์ž‘');

  const goodCount = data.filter((item) => item.emotion >= 3).length;
  const badCount = data.length - goodCount;
  const goodRatio = (goodCount / data.length) * 100;
  return { goodCount, badCount, goodRatio };
}, [data.length]);

// getDiaryAnalysis๋Š” useMemo๋ฅผ ์‚ฌ์šฉํ•ด ๊ฐ’์„ ๋ฆฌํ„ดํ•จ
const { goodCount, badCount, goodRatio } = getDiaryAnalysis;

 

 

์ตœ์ ํ™”2 - ์ปดํฌ๋„ŒํŠธ ์žฌ์‚ฌ์šฉ (React.memo)

state๊ฐ€ ๋ณ€๊ฒฝ๋ผ ๋ฆฌ๋ Œ๋”๋  ํ•„์š” ์—†๋Š” TextView ์ปดํฌ๋„ŒํŠธ๊นŒ์ง€ ๋ Œ๋”๋ง ๋˜๋Š” ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด React.memo๋ฅผ ์‚ฌ์šฉํ•จ

React.memo: ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ์—๊ฒŒ ์—…๋ฐ์ดํŠธ ์กฐ๊ฑด์„ ๊ฑธ์ž

https://ko.legacy.reactjs.org/docs/react-api.html#reactmemo

 

React ์ตœ์ƒ์œ„ API – React

A JavaScript library for building user interfaces

ko.legacy.reactjs.org

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

const CounterA = React.memo(({ count }) => {
  useEffect(() => {
    console.log(`CounterA update - count: ${count}`);
  });
  return <div>{count}</div>;
});

const CounterB = React.memo(({ obj }) => {
  useEffect(() => {
    console.log(`CounterB update - count: ${obj.count}`);
  });
  return <div>{obj.count}</div>;
});

const OptimizeTest = () => {
  const [count, setCount] = useState(1);
  const [obj, setObj] = useState({
    count: 1,
  });

  return (
    <div style={{ padding: 50 }}>
      <div>
        <h2>Counter A</h2>
        <CounterA count={count} />
        <button onClick={() => setCount(count)}>A button</button>
      </div>
      <div>
        <h2>Counter B</h2>
        <CounterB obj={obj} />
        <button
          onClick={() =>
            setObj({
              count: obj.count,
            })
          }
        >
          B button
        </button>
      </div>
    </div>
  );
};

export default OptimizeTest;

 

CounterA ์ปดํฌ๋„ŒํŠธ๋Š” ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ๋•Œ count ๊ฐ’์ด ๋ณ€ํ•˜์ง€ ์•Š์•˜์œผ๋ฏ€๋กœ ๋ Œ๋”๋ง๋˜์ง€ ์•Š์Œ

CounterB ์ปดํฌ๋„ŒํŠธ๋Š” ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ๋•Œ CounterA์™€ ๋‹ฌ๋ฆฌ ๊ฐ’์ด ๋ณ€๊ฒฝ๋๋‹ค๊ณ  ๋ฆฌ๋ Œ๋”๋ง ๋จ โžก๏ธ ๊ฐ์ฒด ์–•์€ ๋ณต์‚ฌ

 

props๊ฐ€ ๊ฐ–๋Š” ๋ณต์žกํ•œ ๊ฐ์ฒด์— ๋Œ€ํ•ด ์–•์€ ๋น„๊ต๋งŒ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ด React.memo์˜ ๊ธฐ๋ณธ ๋™์ž‘์ด๋‹ค. ๋‹ค๋ฅธ ๋น„๊ต ๋™์ž‘์„ ์›ํ•œ๋‹ค๋ฉด, ๋‘ ๋ฒˆ์งธ ์ธ์ž๋กœ ๋ณ„๋„์˜ ๋น„๊ต ํ•จ์ˆ˜๋ฅผ ์ œ๊ณตํ•˜๋ฉด ๋œ๋‹ค.

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

const CounterB = ({ obj }) => {
  useEffect(() => {
    console.log(`CounterB update - count: ${obj.count}`)
  });
  
  return <div>{obj.count}</div>;
}

const areEqual = (prevProps, nextProps) => {
  return prevProps.obj.count === nextProps.obj.count;
}

const MemoizedCounterB = React.memo(CounterB, areEqual)

const OptimizeTest = () => {
  const [obj, setObj] = useState({
    count: 1,
  });
  
  return (
    <div style={{ padding: 50 }}>
      <div>
        <h2>Counter B</h2>
        <MemoizedCounterB obj={obj} />
        <button onClick={() => setObj({ count: obj.count })}></button>
      </div>
    </div>
  );
};

export default OptimizeTest;

 

 

 

 

 

 

๋งˆ๋ฌด๋ฆฌ


React ์ตœ์ ํ™” ๋ฐฉ๋ฒ•์œผ๋กœ useMemo์™€ React.memo์— ๋Œ€ํ•ด ๋ฐฐ์› ๋‹ค.

๋ Œ๋”๋ง์„ ๋งŽ์ด ํ•˜๋ฉด ์„ฑ๋Šฅ์ด ์ €ํ•˜๋˜๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ํ•ญ์ƒ ๋ Œ๋”๋ง์„ ์ตœ์†Œํ™”ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ƒ๊ฐํ•˜๋ฉฐ ์ฝ”๋“œ๋ฅผ ์งœ์•ผ๊ฒ ๋‹ค.