본문 바로가기
react

[React] Hooks함수 정리2(useMemo, useCallback)

by 남민섭 2023. 1. 13.
728x90
반응형

1. useMemo

리액트 성능 최적화

함수형 컴포넌트는 함수이다

jsx를 반환하는 함수

컴포넌트가 렌더링 되는것은 그 컴포넌트 함수를 호출해서 실행되는 것을 말함
함수가 실행 될 때 함수 내부에 선언된 표현식(변수, 다른 함수)도
다시 선언되어 사용됩니다.
컴포넌트는 자신의 state가 변경되거나 부모에게서 받는 props가
변경될 때 마다 리렌더링 됩니다

 

예를들어 state.props가 여러가지라면
state1, state2, state3
state1을 리렌더링 시켜주었는데
state2, state3 도 리렌더링 된다면??

원하는 props만 리렌더링시켜주기 위해 useMemo와 useCallback 함수가 있다

 


useMemo 란?  

컴퍼넌트 성능 최적화에 사용

함수니깐 여기에 정의된 변수도 다시 리렌더링 (재사용 가능)


useMemo의 Memo는 ------> memoization 을 뜻함


memoization는 동일한 값을 리턴하는 함수를 반복적으로 호출해야한다면 처음 값을
계산할때 그 값을 메모리 저장해서 필요할때만 계산하지 않고 메모리에서 꺼내서 재사용하는 기법


자주 필요한 값을 처음 계산할때 캐시에 저장을 해두어 값이 **필요할때마다 
계산하지 않고 캐시에서 꺼내서 재사용


구문) 

 *deps --->의존성 배열 (dependency array)

useMemo(() => {
	return value;
},[deps])

 

원하는 변수만 리렌더링해주고 싶은데 .... 두 매개변수 중에 하나만 변경되도 다 같이 리랜더링 된다

*함수형 컴포넌트는 렌더링을 할경우 ---> component함수가 호출되고 ---> 모든 내부 변수는 초기화됨

↓↓↓↓↓↓↓

function calculate(value){
	return value+1;
}

function FunComponent({value, text}){  //객체 구조분해 할당
    const number = calculate(value);
    return(
        <div>
            {number}
            {text}
        </div>
    )
}



useMemo 실습1 (codeSandBox 하단에 콘솔창 확인)

useMemo 함수 사용하여 각각 리렌더링 시켜 number 관련 콘솔, text 관련 콘솔 내용 따로 출력되게함

 

 

 

App.js

import { useState } from "react";
import ShowState from "./component/ShowState";

function App() {
  const [number, setNumber] = useState(0);
  const [text, setText] = useState("");

  const increaseNumber = () => {
    setNumber(number + 1);
  };
  const decreaseNumber = () => {
    setNumber(number - 1);
  };
  const onChange = (e) => {
    setText(e.target.value);
  };
  return (
    <div className="App">
      <div>
        <button onClick={increaseNumber}>+1</button>
        <button onClick={decreaseNumber}>-1</button>
        <input type="text" paaceholder="lastname" onChange={onChange} />
      </div>
      <ShowState number={number} text={text} />
    </div>
  );
}

export default App;

 

ShowState.js

import React, { useMemo } from "react";

const getNumber = (number) => {
  console.log("숫자가 변동되었습니다.");
  return number;
};
const getText = (text) => {
  console.log("글자가 변동되엇습니다.");
  return text;
};
const ShowState = ({ number, text }) => {
  const showNumber = useMemo(() => getNumber(number), [number]);
  const showText = useMemo(() => getText(text), [text]);
  return (
    <div>
      {showNumber}
      <br />
      {showText}
    </div>
  );
};

export default ShowState;

 


 

useMemo 실습2 (codeSandBox  하단에 콘솔창 확인)

useMemo함수 사용하여 숫자 변경할때는 console창에 출력내용 안뜨고

나라 이동 버튼 클릭시 console창 출력되게 함

 

 

 

App.js

import MemoComponent from "./component/MemoComponent";

function App() {
  return (
    <div className="App">
      <MemoComponent />
    </div>
  );
}

export default App;

 

MemoComponent.js

import React, { useEffect, useMemo, useState } from "react";

const MemoComponent = () => {
  const [number, setNumber] = useState(0);
  const [isKorea, setIsKorea] = useState(true);
  //원시형타입 vs 객체타입
  /* const location = {
        country: isKorea ? "한국" : "외국"
    } */
  const location = useMemo(() => {
    return {
      country: isKorea ? "한국" : "외국"
    };
  }, [isKorea]);
  //useEffect(콜백함수,[desp])
  //useEffect ======> 마운트될때, 업데이트(리렌더링), 언마운트일때
  useEffect(() => {
    console.log("풍풍풍, userEffect호출");
  }, [location]);
  return (
    <div>
      <h2>좋아하는 숫자는?</h2>
      <input
        type="number"
        value={number}
        onChange={(e) => setNumber(e.target.value)}
      />
      <h2>이동하실까요?</h2>
      <p>나라: {location.country}</p>
      <button onClick={() => setIsKorea(!isKorea)}>이동</button>
    </div>
  );
};

export default MemoComponent;

 

 

추가내용

원시(Primitive)타입 (기본형)
Number, String, Boolean, Null, undefined, BigInt

 

const number =20
const number2 = 20


number === number2   

 

true 나옴

 

객체(Object)타입 참조형 
원시타입을 제외한 모든것


const objnumber = {
number:20
}

const objnumber2 = {
number:20
}

objnumber === objnumber2


false 나옴. 이유는 객체가 만들어진 메모리 주소 번지가 다름


2.useCallback

useMemo는 함수의 결과값을 재사용(결과값을 메모리에 저장) 하고

useCallback은 특수함수(함수자체를 메모리에 저장)를 새로 만들지 않고 재사용한다

 

구문)

useCallback((num)=>{
	return num+1;
}, [deps])

 

ex)

function Component() {
	const calulate = (num) => {
    	return num + 1
    },[item]}
    return(
    	<div>{value}</div>
    )
}

 

useCallback함수를 이용한 실습 1

 

 

App.js

import React, { useCallback, useState } from 'react';
import List from './components/List';

const App = () => {
    const [number, setNumber] = useState(1);
    const [dark, setDark] = useState(false);
    const theme={
        backgroundColor: dark? "#333" : "#fff",
        color: dark? "#fff" : "#333"
    }
    const getItems = useCallback(() => { //useCallback함수 사용
        return [number, number + 1, number + 2] //[1,2,3]
    },[number])
    
    // const getItems = useMemo(() =>  useMemo함수 사용
    //     (value) => {
    //         return [number, number + 1, number + 2] //[1,2,3]
    //     },[number])
    
    return (
        <div style={theme}>
            <input type="number" value={number}
            onChange={e=>setNumber(Number(e.target.value))}
            />
            <button onClick={()=>{setDark(!dark)}}>테마변경</button>
            <List getItems={getItems}/>
        </div>
    );
};

export default App;

 

 

List.js

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

const List = ({getItems}) => { //getItems 여기로 받았음 꿀꺽~
    const [items, setItems] = useState([]);
    useEffect(()=>{
        setItems(getItems()) //배열을 리턴해줌[1,2,3]
        console.log("숫자가 변동되었습니다.")
    },[getItems])
    return (
        <div>
            {items.map((item,index)=><div key={index}>{item}</div>)}
            {/* [1,2,3] map으로 돌려줌 map은 새로운 배열로 바꿔줌*/}
            {/* <div></div>
                <div></div>
                <div></div> 이렇게 담김 */}
        </div>
    );
};

export default List;

 

useCallback함수를 이용한 실습 2

 

 

App.js

import React, { useCallback, useState } from 'react';
import Box from './components/Box';
const App = () => {
    const [size, setSize] = useState(100);
    const [dark, setDark] = useState(false);
    const createBox = useCallback(() => {
        return {
            backgroundColor: 'pink',
            width:`${size}px`,
            height: `${size}px`
        }
    },[size])
    const style = {
        backgroundColor: dark ? "#333" : "#fff",
        color: dark? "#fff" : "#333"
    }
    return (
        <div style={style}>
            <input type="number" 
            value={size} onChange={e=>setSize(e.target.value)}/>
            <Box createBox={createBox} />
            <button onClick={()=>setDark(!dark)}>변경</button>
        </div>
       
    );
};

export default App;

 

Box.js

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

const Box = ({createBox}) => {
    const [style, setStyle] = useState({});
    useEffect(()=>{
         console.log("박스키우기")
         setStyle(createBox())
    },[createBox])
    return (
        <div style={style}>
            
        </div>
    );
};

export default Box;

 

728x90
반응형

댓글