[React] UseMemo() UseCallbak() 차이

DONNIE·2023년 9월 7일
0

React

목록 보기
21/26

Memoizition

기존에 수행한 연산의 결과값을 어딘가에 저장해두고 동일한 입력이 들어오면 재활용하는 기법
중복 연산을 방지해주기 때문에 애플리케이션의 성능 최적화

📌 UseMemo

메모이제이션된 값을 반환하는 함수
deps로 지정한 값이 변화게되면 함수를 실행하고, 함수의 반환 값을 반환해줌
useMemo는 deps값이 변하면 함수를 실행하는것이라면 이건


export default functino App() {

	const [ex, setEx] = useState(0);
    const [why, setWhy] = useStatue(0);
    
    1) useMemo(()-> {console.log(ex), [deps]});
    2) console.log(ex)
    
    return (
    	<>
        <button onClick=>{()=>setEx((curr1=>curr1+1))}>X</button>
        <button onClick=>{()=>setWhy((curr2=>curr2+1))}>Y</button>
        </>
    )
}
  • 1)을 사용할 경우 X라는 버튼을 클릭했을 떄 setEx에 의해 ex의 값을 1씩 증가시키는데, ex의 값이 변하기 때문에 콘솔로그가 실행됨
  • 2)는 상태값에 상관없이 컴포넌트가 리렌더링 될 경우 항상 실행됨

📌 useCallback()

메모이제이션된 함수를 반환함
useCallback 은 함수를 반환하기 때문에 그 함수를 가지는 const 변수에 초기화하는 것이 일반적
자식 컴포넌트에 props로 함수를 전달하는 경우
외부에서 값을 가져오는 API를 호출하는 경우

  1. 자식 컴포넌트에 props로 함수를 전달하는 경우
const sampleFunction1 = function() { return 5 }
const sampleFunction2 = function() { return 5 }

console.log(sampleFunction1 === sampleFunction2) 
// 함수는 참조값으로 비교하기떄문에 false 
  • 위와 같은 이유로 컴포넌트에서 특정 함수를 정의할 경우 각각의 함수들은 모두 고유한 함수가 됨
  • 이런 고유한 함수가 생성될 경우, 부모를 통해 props에 함수를 전달받는 자식 컴포넌트에서는 props가 변경되었다고 판단해 리렌더링이 발생함
function App() {
	const [name, setName] = useState('')
    const onSave = () => {};
    
    return (
    	<div className="App">
        	<input 
             type="text"
             value={name}
             onChange={(e)=>setName(e.target.valu)}
             />
             <Profile onSave={onSave} />
        </div>
    )
}
  • useCallback을 사용하지 않을 경우, name이 변경되어 리렌더링이 발생하면 onSave함수가 새로 만들어지고, Profile 컴포넌트의 props로 onSave 함수가 새로 전잘됨
    이 때 Profile 컴포넌트에서 use?Memo를 사용해도 이전 onSave와 이후 on?Save가 같은 값을 반환하지만 참조가 다른 함수가 되어 리렌더링이 일어나는것이다.
function App() {
	const [name, setName] = useState('')
    const onSave = useCallback(() => {
    	console.log(name);
    },[name]);
    
    return (
    	<div className="App">
        	<input 
             type="text"
             value={name}
             onChange={(e)=>setName(e.target.valu)}
             />
             <Profile onSave={onSave} />
        </div>
    )
}
  • 위와같이 onSave라는 함수를 재사용하는것으로 자식 컴포넌트의 리렌더링을 방지한다.
  1. 외부에서 값을 가져오는 API를 호추하는 경우
function Profile({userId}) {

	const [user, setUser] = useState(null);
    
    const fetchUser = () => {
    	fetch('url')
        .then((response)=> response.json())
        .then(({user})=>user);
     }   
        useEffect(()=>{
        	fetchUser().then((user)=>setUser(user));
        },[fetchUser])
    }
  • 위의 코드는 fetchUser함수가 변경될때만 외부에서 API를 가져와 useEffect가 실행된다.
    여기서 문제점은 Profile이라는 컴포넌트가 리렌더링이 발생할 경우 fetchUser가 실행되고, 다시 user상태값이 바뀌어 다시 리렌더링이 일어나서 무한루프에 빠지게 됨

  • useCallvack을 사용하여 fetchUser 함수의 참조값을 동일하게 유지시킴

 function Profile({userId}) {

	const [user, setUser] = useState(null);
    
    const fetchUser = useCallback(() => {
    	fetch('url')
        .then((response)=> response.json())
        .then(({user})=>user);
    },[userId]);
       
        useEffect(()=>{
        	fetchUser().then((user)=>setUser(user));
        },[fetchUser])
}
  • API의 옵션으로 사용되는 userId가 변동될때만 fetchUser에 새로운 함수가 할당되도록 설정하고, 그게 아니면 동일한 함수가 실행되는 걸 방지
profile
후론트엔드 개발자

0개의 댓글