불필요한 메모아이제이션은 메모아이제이션을 아예 하지않은것만큼 나쁘다!!
(an unnecessary memoization is as bad as not memoizing at all!)
- 계산 비용이 높은 함수일 경우
- 컴포넌트의 불필요한 랜더링을 방지하고 싶을떄
React에서 컴포넌트 렌더링 최적화를 위해 React.memo와 useMemo를 사용합니다. 이를 통해 컴포넌트가 동일한 props를 가질 때 렌더링을 방지하고 성능을 향상시킬 수 있습니다.
1. React.memo 활용 예시
import React from 'react';
const MyComponent = React.memo(({ name }) => {
console.log('컴포넌트 랜더링 확인용');
return <div>Hello, {name}!</div>;
});
export default MyComponent;
2. useMemo 활용 예시
import React, { useState, useMemo } from 'react';
const NumberList = ({ numbers }) => {
// 합계 계산 결과를 useMemo로 메모아이제이션
const sum = useMemo(() => {
return numbers.reduce((acc, val) => acc + val, 0);
}, [numbers]); // numbers 배열이 변경될 때만 다시 계산
return (
<div>
<h2>리스트</h2>
<ul>
{numbers.map((number, index) => (
<li key={index}>{number}</li>
))}
</ul>
<p>Sum: {sum}</p>
</div>
);
};
const App = () => {
const [numbers, setNumbers] = useState([1, 2, 3, 4, 5]);
const addNumber = () => {
const newNumber = Math.floor(Math.random() * 10) + 1;
setNumbers([...numbers, newNumber]);
};
return (
<div>
<button onClick={addNumber}>+</button>
<NumberList numbers={numbers} />
</div>
);
};
export default App;
네트워크 요청 결과를 메모이제이션하여 동일한 요청을 여러 번 보내지 않고 캐싱된 결과를 사용할 수 있습니다. 이렇게 하면 서버 부하를 줄이고 응답 시간을 단축할 수 있습니다.
import { useState, useEffect } from 'react';
const fetchData = async (url) => {
const response = await fetch(url);
const data = await response.json();
return data;
};
const DataFetchingComponent = () => {
const [data, setData] = useState(null);
useEffect(() => {
// 데이터를 가져와서 메모아이제이션
const fetchDataAndMemoize = async () => {
const cachedData = localStorage.getItem('cachedData');
if (cachedData) {
setData(JSON.parse(cachedData));
} else {
const result = await fetchData('https://localhost:3000/data');
setData(result);
localStorage.setItem('cachedData', JSON.stringify(result));
}
};
fetchDataAndMemoize();
}, []);
if (!data) {
return <div>로딩중...</div>;
}
return (
<div>
<h2>임시데이터:</h2>
<div>{JSON.stringify(data, null, 2)}</div>
</div>
);
};
export default DataFetchingComponent;
💡 순수함수란 ?
- 동일한 입력에 대해 항상 동일한 출력을 반환하는 함수
- 아래 요소들을 포함한 부작용을 일으키지 않는 함수 .
(네트워크 요청, data mutation, 파일 로깅, state 변경)
Custom Hook과 Context API를 사용해보자!
실제 진행한 프로젝트에서 예시를 가지고 왔다.
import { useEffect } from 'react';
const usePreventGoingBack = goBackCallback => {
const preventGoBack = () => {
history.pushState(null, '', location.href);
goBackCallback?.();
};
useEffect(() => {
history.pushState(null, '', location.href);
window.addEventListener('popstate', preventGoBack);
return () => {
window.removeEventListener('popstate', preventGoBack);
};
}, []);
};
export default usePreventGoingBack;
문제점
: 새로고침을 할때마다 자꾸 landing Page로 돌아가게되었었음해결한 방법
: // Context / auth.js
import TokenService from 'Repository/TokenService';
import { useContext, useState, createContext, useEffect } from 'react';
const AuthContext = createContext();
export const useAuth = () => useContext(AuthContext);
function AuthProvider({ children }) {
const [accessToken, setAccessToken] = useState(TokenService.getToken());
useEffect(() => {
const token = TokenService.getToken();
if (!token) return;
setAccessToken(token);
}, []);
const login = token => {
TokenService.setToken(token);
setAccessToken(token);
};
const logout = () => {
TokenService.removeToken();
setAccessToken(null);
};
return (
<AuthContext.Provider value={{ accessToken, login, logout }}>
{children}
</AuthContext.Provider>
);
}
export default AuthProvider;
// PrivateRoute.js
import { useAuth } from 'Context/auth';
import { Navigate } from 'react-router-dom';
const PrivateRoute = ({ children }) => {
const {accessToken} = useAuth(); // 변경사항
return accessToken ? children : <Navigate to={`/`} />;
};
export default PrivateRoute;
<AuthProvider>
<GlobalStyles />
<RouterProvider router={router} />
</AuthProvider>
``