useEffect, useLayoutEffect, useReducer , useMemo, useCallback
1. useEffect
useEffect는 컴포넌트가 렌더링 된 후 비동기적으로 실행됩니다. 브라우저가 화면을 업데이트한 후에 실행되므로, 레이아웃 계산이나 DOM 조작보다는 데이터 가져오기, 구독 설정, 타이머 설정 등에 적합합니다.
2. useLayoutEffect
useLayoutEffect는 컴포넌트가 렌더링 된 후, 브라우저가 화면을 업데이트하기 전에 동기적으로 실행됩니다. 따라서 레이아웃 계산, DOM 측정 또는 동기적인 DOM 조작이 필요한 경우에 적합합니다.
- 실행 시점:
- useEffect: 컴포넌트가 렌더링되고 화면이 업데이트된 후 비동기적으로 실행됩니다.
- useLayoutEffect: 컴포넌트가 렌더링 된 후, 화면이 업데이트되기 전에 동기적으로 실행됩니다.
- 용도:
- useEffect: 비동기 작업(데이터 가져오기, 구독 설정 등)이나 DOM 업데이트 후에 발생해야 하는 작업에 사용됩니다.
- useLayoutEffect: 레이아웃 계산, DOM 측정 또는 화면에 그려지기 전에 필요한 동기적인 DOM 조작에 사용됩니다.
언제 useLayoutEffect를 사용해야 하나요?
useLayoutEffect는 주로 다음과 같은 경우에 사용됩니다:
- DOM 요소의 크기나 위치를 측정하고, 그 정보를 기반으로 다른 동작을 수행해야 할 때.
- 화면이 깜빡이는 문제를 방지하기 위해, DOM 조작이 화면에 표시되기 전에 이루어져야 할 때.
일반적으로, useEffect를 사용하여 원하는 작업이 정상적으로 이루어지면 useLayoutEffect는 필요하지 않습니다. 그러나 특정 레이아웃이나 DOM 조작이 필요할 경우 useLayoutEffect를 고려해야 합니다.
# useEffect
https://ko.legacy.reactjs.org/docs/hooks-effect.html
공식문서내용
데이터 가져오기, 구독(subscription) 설정하기, 수동으로 React 컴포넌트의 DOM을 수정하는 것까지 이 모든 것이 side effects입니다. 이런 기능들(operations)을 side effect(혹은 effect)라 부르는 것이 익숙하지 않을 수도 있지만, 아마도 이전에 만들었던 컴포넌트에서 위의 기능들을 구현해 보았을 것입니다.
메모리 누수란
메모리 누수는 컴퓨터 프로그램이 메모리를 할당했지만 해제하지 않고 그대로 두는 상황을 가리킵니다. 일반적으로 프로그램이 동적으로 메모리를 할당할 때, 사용이 끝난 후에는 해당 메모리를 명시적으로 해제해야 합니다. 그러나 메모리 누수가 발생하면 프로그램이 사용하지 않는 메모리를 계속 보유하고 있게 되어 메모리 사용량이 계속 증가하고, 결국에는 시스템 성능에 부정적인 영향을 미칠 수 있습니다.
메모리 누수는 주로 다음과 같은 상황에서 발생할 수 있습니다:
- 메모리를 할당한 후, 해당 메모리를 해제하지 않은 경우.
- 메모리를 할당한 후, 프로그램이 해당 메모리를 사용하지 않는 상황에서도 해제하지 않은 경우.
- 데이터 구조체나 객체가 서로 참조를 가지고 있어 해제되지 않는 경우 (이를 '순환 참조'라고 합니다).
https://ko.wikipedia.org/wiki/%EB%A9%94%EB%AA%A8%EB%A6%AC_%EB%88%84%EC%88%98
위키백과
컴퓨터 과학에서 메모리 누수(memory leak) 현상은 컴퓨터 프로그램이 필요하지 않은 메모리를 계속 점유하고 있는 현상이다. 할당된 메모리를 사용한 다음 반환하지 않는 것이 누적되면 메모리가 낭비된다. 즉, 더 이상 불필요한 메모리가 해제되지 않으면서 메모리 할당을 잘못 관리할 때 발생한다.[1] 일부 서적에서 메모리 손실이라는 용어로 뜻을 옮기기도 하지만 [2] leak라는 표현은 단순히 잃는 것 이상의 개념이므로 누수라는 표현이 더 정확하다.
https://react.dev/reference/react/useEffect
useEffect(setup, dependencies?)
매개변수
- setup: Effect의 로직이 포함된 기능입니다. 설정 함수는 선택적으로 정리 함수를 반환할 수도 있습니다. 컴포넌트가 DOM에 추가되면 React는 설정 기능을 실행합니다. 변경된 종속성을 사용하여 다시 렌더링 할 때마다 React는 먼저 이전 값을 사용하여 정리 기능(제공한 경우)을 실행한 다음 새 값을 사용하여 설정 기능을 실행합니다. 구성 요소가 DOM에서 제거된 후 React는 정리 기능을 실행합니다.
- 선택 사항 dependencies : 코드 내부에서 참조되는 모든 반응 값의 목록입니다 setup. 반응형 값에는 props, state 및 구성 요소 본체 내부에 직접 선언된 모든 변수와 함수가 포함됩니다. Linter가 React용으로 구성된 경우 모든 반응 값이 종속성으로 올바르게 지정되었는지 확인합니다. 종속성 목록은 항목 수가 일정해야 하며 처럼 인라인으로 작성되어야 합니다 [dep1, dep2, dep3]. React는 비교를 사용하여 각 종속성을 이전 값과 비교합니다 Object.is. 이 인수를 생략하면 구성 요소를 다시 렌더링할 때마다 Effect가 다시 실행됩니다.
주의사항
- useEffectHook이므로 컴포넌트의 최상위 수준이나 자체 Hook에서만 호출할 수 있습니다. 루프나 조건 내에서는 호출할 수 없습니다. 필요한 경우 새 구성 요소를 추출하고 상태를 해당 구성 요소로 옮깁니다.
- 일부 외부 시스템과 동기화하려는 것이 아니라면 효과가 필요하지 않을 수도 있습니다.
- Strict 모드가 켜져 있으면 React는 첫 번째 실제 설정 전에 추가 개발 전용 설정+정리 주기를 한 번 더 실행합니다. 이는 정리 논리가 설정 논리를 "미러링"하고 설정이 수행하는 모든 작업을 중지하거나 실행 취소하는지 확인하는 스트레스 테스트입니다. 이로 인해 문제가 발생하면 정리 기능을 구현하십시오.
- 종속성 중 일부가 구성 요소 내부에 정의된 개체 또는 함수인 경우 Effect가 필요한 것보다 더 자주 다시 실행될 위험이 있습니다. 이 문제를 해결하려면 불필요한 개체 및 함수 종속성을 제거하세요. Effect 외부에서 상태 업데이트 와 비반응형 로직을 추출할 수도 있습니다.
- Effect가 상호 작용(예: 클릭)으로 인해 발생하지 않은 경우 React는 일반적으로 Effect를 실행하기 전에 브라우저가 업데이트된 화면을 먼저 그리도록 합니다. 효과가 시각적인 작업(예: 도구 설명 위치 지정)을 수행하고 지연이 눈에 띄는 경우(예: 깜박임) useEffect로 바꾸세요 useLayoutEffect.
- Effect가 상호 작용(예: 클릭)으로 인해 발생한 경우에도 브라우저는 Effect 내부의 상태 업데이트를 처리하기 전에 화면을 다시 칠할 수 있습니다. 일반적으로 그것이 당신이 원하는 것입니다. 그러나 브라우저가 화면을 다시 그리는 것을 차단해야 하는 경우 useEffect로 바꿔야 합니다 useLayoutEffect.
- 효과는 클라이언트에서만 실행됩니다. 서버 렌더링 중에는 실행되지 않습니다.
useEffect(() => {
fetch('url')
.then((res) => res.json())
.then((json) => setData(json));
}, []);
useEffect(() => {
axios.get('url').then((res) => setData(res.data));
}, []);
const getData = async () => {
const res = await fetch('url');
const json = await res.json();
setData(json);
};
useEffect(() => {
getData();
}, []);
const getData = async () => {
const res = await axios.get('url');
setData(res.data);
};
useEffect(() => {
getData();
}, []);
비동기
https://fullstack-eun.tistory.com/103
로컬스토리지
https://fullstack-eun.tistory.com/69
# 성능최적화
3. useMemo
컴포넌트 성능 최적화를 위해 사용되는 훅(Hook)입니다. 컴포넌트가 리렌더링될 때 매번 실행되지 않고, 의존성 배열에 명시된 값이 변경될 때만 계산된 값을 다시 생성하여 성능을 최적화할 수 있습니다. useMemo는 계산 비용이 높은 작업이나 불필요한 리렌더링을 방지하는 데 유용합니다.
https://react.dev/reference/react/useMemo
추가 설치
yarn add devtools
const memoizedValue = useMemo(() => {
// 연산 비용이 높은 작업
return 계산된 값;
}, [의존성 배열]);
- 의존성 배열: 두 번째 인자로 전달되는 배열로, 배열에 포함된 값이 변경될 때만 첫 번째 인자의 함수가 다시 실행됩니다. 이 배열에 포함된 값이 변경되지 않는 한, 이전에 계산된 값이 재사용됩니다.
- 메모이제이션: useMemo는 이전에 계산된 값을 저장해두고, 의존성 배열의 값이 변하지 않으면 저장된 값을 반환하여 불필요한 연산을 피합니다.
- 성능 최적화: 주로 연산이 비싼 함수나 렌더링이 많이 일어나는 컴포넌트에서 사용합니다.
- 복잡한 계산이 자주 일어나는 경우.
- 렌더링 성능을 최적화하고 싶을 때.
- 컴포넌트 리렌더링에 영향을 줄 수 있는 값이 변경되지 않았을 때, 재계산을 피하고 싶을 때.
4. useCallback
컴포넌트 성능 최적화를 위해 사용되는 또 다른 훅(Hook)으로, 함수의 재생성을 방지하고 메모이제이션을 통해 불필요한 리렌더링을 줄이는 역할을 합니다. 주로 자식 컴포넌트에 콜백 함수를 전달하거나, 특정 의존성이 변경되지 않는 한 같은 함수 참조를 유지해야 할 때 사용됩니다.
const memoizedCallback = useCallback(() => {
// 콜백 함수의 로직
}, [의존성 배열]);
- 함수 메모이제이션: useCallback은 컴포넌트가 리렌더링될 때마다 함수가 새로 생성되는 것을 방지하고, 의존성 배열에 포함된 값이 변경되지 않는 한 이전에 생성된 함수를 재사용합니다.
- 의존성 배열: 두 번째 인자로 전달되는 배열에 포함된 값이 변경될 때만 함수가 새로 생성됩니다. 이 배열이 비어 있으면 처음 한 번만 함수가 생성되고 이후에는 동일한 함수가 유지됩니다.
- 콜백 최적화: useCallback은 주로 자식 컴포넌트에 함수가 props로 전달될 때 사용됩니다. 이를 통해 자식 컴포넌트가 불필요하게 리렌더링되는 것을 방지할 수 있습니다.
- 함수가 자식 컴포넌트에 전달될 때, 그 함수가 매번 새로 생성되어 불필요한 리렌더링이 발생하는 경우.
- 함수가 의존성에 따라 변하지 않는다면, 같은 함수 참조를 유지하고 싶을 때.
# 상태 관리
5. useReducer
useReducer는 React Hooks 중 하나로, 상태를 관리하기 위한 함수입니다. 이 Hook은 보통 복잡한 상태 관리나 여러 개의 하위 값들을 갖는 상태를 다룰 때 사용됩니다. useState와 유사하지만, 더 복잡한 상태 로직을 다루기 위한 강력한 대안으로 사용됩니다.
useReducer를 사용하면 상태를 변경하는 함수(리듀서)를 정의하고, 이 함수를 통해 상태를 업데이트할 수 있습니다. 리듀서는 현재 상태와 업데이트를 위한 액션을 받아서 새로운 상태를 반환합니다.
간단한 예제를 통해 useReducer를 설명해보겠습니다. 예를 들어, 계산기 애플리케이션을 만든다고 가정해봅시다. 이 애플리케이션은 현재 값과 사용자가 더하거나 뺄 값을 받아서 결과를 계산해야 합니다.
import React, { useReducer } from 'react';
// 초기 상태
const initialState = {
count: 0
};
// 리듀서 함수
const reducer = (state, action) => {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
return state;
}
};
const Counter = () => {
// useReducer를 사용하여 상태와 리듀서를 연결합니다.
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: 'increment' })}>Increment</button>
<button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button>
</div>
);
};
export default Counter;
useReducer는 reducer 함수와 초기 상태 initialState를 인자로 받습니다. 그리고 dispatch 함수를 반환하는데, 이 함수를 통해 액션을 호출하여 상태를 업데이트할 수 있습니다.
이제 reducer 함수 내에서 액션의 타입에 따라 상태를 어떻게 업데이트하는지 확인할 수 있습니다. 위의 예제에서는 'increment'와 'decrement' 액션에 대해 각각 count를 증가시키거나 감소시키는 로직을 구현했습니다.
이러한 방식으로, useReducer를 사용하면 복잡한 상태 로직을 간결하게 표현할 수 있습니다.
# 사용자 정의 훅
React 애플리케이션에서 중복되는 로직을 재사용하고 코드를 더 간결하고 관리하기 쉽게 만들기 위해서 사용
형식)
export const use사용자정의 = () => {
const [state, setState] = useState();
const 함수 = () => {
setState( ???? );
};
return { state , 함수 , 내보는 값 };
};
useFetch
import { useState, useEffect } from 'react';
const useFetch = (url) => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
setLoading(true);
try {
const response = await fetch(url);
const result = await response.json();
setData(result);
} catch (error) {
setError(error);
} finally {
setLoading(false);
}
};
fetchData();
}, [url]);
return { data, loading, error };
};
export default useFetch;
Test 컴포넌트
import React from 'react';
import useFetch from './useFetch';
const Test = () => {
const { data, loading, error } = useFetch('https://jsonplaceholder.typicode.com/users');
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<ul>
{data.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
};
export default Test;
# .env
환경 변수를 정의하고 관리하기 위한 텍스트 파일입니다. .env 파일을 사용하면 프로젝트 내에서 민감한 정보나 환경별 설정을 코드에서 분리하여 관리할 수 있습니다.
.env 파일은 환경 변수를 정의하는 파일로, 애플리케이션이 실행될 때 이러한 환경 변수들을 시스템에 적용합니다.
일반적으로 API 키, 데이터베이스 접속 정보, 애플리케이션 모드(개발/프로덕션), 서버 주소 등 환경별로 변경될 수 있는 값들을 이 파일에 저장합니다.
.evn
VITE_API_KEY=your_api_key_here
VITE_API_URL=https://api.example.com
NODE_ENV=development
PORT=3000
KEY=VALUE 형식으로 변수를 정의합니다. 공백 없이 변수와 값을 정의해야 하며, 값에 문자열이 포함될 경우 따옴표를 사용할 수 있습니다.
VITE_API_KEY=your_api_key_here
your_api_key_here 는 '' ,"" , ; 를 사용하지 않습니다.
맨앞에 VITE_ 필수
VITE_ 접두어: 모든 환경 변수는 반드시 VITE_로 시작해야 합니다. 그렇지 않으면 import.meta.env에서 해당 변수를 인식하지 못합니다.
개발, 테스트, 프로덕션 등 다양한 환경에서 실행됩니다. 각 환경에서는 설정 값이 달라질 수 있습니다. 예를 들어, 개발 환경에서는 로컬 서버를 사용하고, 프로덕션 환경에서는 실제 서버를 사용할 수 있습니다. .env 파일을 사용하면 각 환경에 맞는 변수를 쉽게 설정할 수 있습니다.
- .env.development: 개발 환경 설정
- .env.production: 프로덕션 환경 설정
민감한 정보를 하드코딩하지 않으면, 코드의 가독성 및 유지보수성이 향상됩니다. 중요한 설정 값들은 .env 파일에서 관리되고, 코드에서는 process.env 또는 import.meta.env 등을 통해 간접적으로 참조
- 보안 강화: 민감한 정보를 코드에서 분리해 외부에 노출되지 않도록 보호.
- 유지보수성: 환경별로 설정을 관리할 수 있어 코드의 유지보수성을 높임.
- 재사용성: 환경마다 같은 코드를 사용하고, 설정 값만 달리 적용할 수 있음.
- 코드 간소화: 코드에서 하드코딩하지 않고, process.env 또는 import.meta.env 등을 통해 간접 참조함.
.gitignore에 .env 추가
보안상의 이유로 .env 파일이 Git에 커밋되지 않도록 .gitignore 파일에 추가
myapp/
├── node_modules/
├── public/
├── src/
├── .env <-- 이 위치에 있어야 함
├── package.json
└── ...
컴포넌트
const apiKey = import.meta.env.VITE_API_KEY;
console.log('API Key:', apiKey);
'React' 카테고리의 다른 글
[ React ] 06. router 라우터 (0) | 2024.05.22 |
---|---|
[ React ] 05. style , 스타일 (0) | 2024.05.20 |
[ React ] 03. useRef (0) | 2024.05.09 |
[ React ] 02. props , PropTypes, map , events, useState (0) | 2024.05.09 |
[ React ] 01. react 개념 (0) | 2024.04.23 |