미들웨어는 웹 개발에서 새로운 개념은 아닙니다. 일반적으로 Express.js와 같은 백엔드 프레임워크와 관련이 있으며 인증, 로깅 등이 많이 포함됩니다. 내재적인 이점으로 인해 미들웨어는 프론트엔드에서 상당한 인기를 얻고 있습니다.
React와 같은 프론트엔드 프레임워크는 상태 관리 중에 복잡한 기능을 처리하는 방법으로 채택하고 있습니다. 이 안내서에서는 React에서 미들웨어의 개념을 살펴보고 React 앱의 기능을 향상시키고 응용 프로그램 흐름을 효과적으로 관리하는 방법을 알려드리겠습니다.
최종적으로 React 미들웨어가 무엇이며 Redux Thunk와 함께 구현하는 방법에 대해 잘 이해하게 될 것입니다.
React 미들웨어 간단히 이해하기: 응용 프로그램 로직을 간소화하기
미들웨어란 무엇인가?
이름에서 알 수 있듯이 미들웨어는 응용 프로그램의 다양한 구성 요소 사이에 위치한 레이어입니다. 이는 없는 경우 여기에서 처리 및 기능 레이어를 제공합니다. 미들웨어는 한 구성 요소에서 다른 구성 요소로 흐르는 요청을 가로채고 특정 작업을 수행할 수 있도록 해줍니다. 완료되면 수정된 요청을 다음 미들웨어 또는 목적지로 전달합니다.
이는 주로 백엔드에서 사용되는 개념입니다. 그러나 앞서 언급했듯이 React에서 유사한 목적으로 채택되었습니다. 이제 React에서 미들웨어가 무엇을 의미하는지 자세히 살펴보겠습니다.
React의 미들웨어
React에서 미들웨어는 정의한 순서대로 차례로 실행되는 일련의 함수로 구현됩니다. 각 함수는 앱의 상태와 액세스에 대한 액션에 접근할 수 있습니다. 따라서 이 함수들은 새로운 액션을 수정하고 디스패치할 수 있습니다.
React에서 상태가 변경되면, 애플리케이션은 액션을 디스패치하고, 이는 Reducer에 의해 처리됩니다. Reducer는 새로운 상태를 반환하며, 이 상태는 저장되고 애플리케이션으로 전달됩니다.
React 미들웨어는 디스패치된 액션과 Reducer 사이에 위치하여, 액션이 Reducer에 도달하기 전에 가로챕니다. 그런 다음 이 과정에 후킹하여 이 액션에 대한 코드를 실행할 수 있도록 해줍니다. 예를 들어, 로그를 남기거나 API 호출을 할 수 있습니다.
이 작업이 완료되면 수정된 액션을 Reducer로 전달합니다(체인에 다른 미들웨어가 없다면).
React에서의 미들웨어 예시
React 미들웨어는 주로 복잡한 상태 관리 React 라이브러리인 Redux에서 찾을 수 있습니다. Redux에는 두 가지 주요 미들웨어 유형이 있습니다:
- Thunk – 이 미들웨어를 사용하여 액션을 수정하는 방법에 대해 더 깊이 다룰 것입니다.
- Saga.
각각은 아래에서 React에서 미들웨어의 용도를 살펴볼 때 볼 수 있듯이 액션에 대한 다양한 유형의 수정을 처리합니다. React Query와 같은 다른 React 라이브러리도 미들웨어를 사용합니다(자세한 내용은 나중에 다룰 예정입니다).
이것을 구현하는 방법을 살펴보기 전에, React에서 미들웨어의 다양한 용도를 살펴보겠습니다.
React에서의 미들웨어 용도
React 미들웨어은 다음과 같은 사용 사례에 유용합니다:
디버깅 및 로깅
React 미들웨어는 응용 프로그램 개발 중 현재 상태, 액션 및 기타 데이터와 같은 정보를 기록하는 데 사용할 수 있습니다. 또한 잠재적인 버그와 오류를 조기에 해결하기 위해 유용할 수 있습니다.
Redux Logger(리덕스용)를 사용하면 이 작업을 수행할 수 있습니다. 이는 리덕스 액션 및 상태 변경을 기록하여 쉬운 디버깅을 지원합니다. 각 디스패치된 액션을 가로채서 이전 상태, 액션 및 다음 상태를 기록합니다.
인가 및 인증
상태를 업데이트하기 전에 사용자를 인증하려면 Redux Thunk 또는 Saga를 사용하여 인증 워크플로우를 처리할 수 있습니다. 액션을 가로채면 이 미들웨어를 사용하여 토큰을 저장하고, 액션을 디스패치하기 전에 인증을 확인하거나 토큰을 새로 고칠 수 있습니다.
다시 말해, 이러한 미들웨어는 특정 경로에 접근할 권한이 있는지 여부를 확인하는 데 유용합니다.
이벤트 기반 작업
React 리듀서는 동기 코드를 실행하도록 설계되었습니다. 이것은 비동기 작업을 시도하면 작동하지 않는다는 것을 의미합니다. Redux Thunk와 같은 React 미들웨어를 사용하면 해당 액션을 잡아서 API 호출과 같은 비동기 작업을 수행한 후 리듀서로 진행할 수 있습니다.
데이터 캐싱
React Query(다른 React 미들웨어)는 애플리케이션 데이터 캐싱에 효과적인 도구로 사용될 수 있습니다. 필요할 때 API 응답을 자동으로 캐시하고 다시 유효성을 검사합니다. 이로써 캐시에서 필요한 정보를 확인하여 중복되는 API 호출을 피할 수 있습니다.
성능 향상
React 미들웨어는 불필요한 작업을 나중에 실행하고 이벤트를 디바운스하며 특정 작업을 일괄 처리함으로써 애플리케이션의 성능을 향상시킬 수도 있습니다. API 응답을 캐시함으로써 React Query는 React 앱의 성능도 향상시킵니다.
React에서 미들웨어 사용하는 방법
Redux는 React 애플리케이션에서 전역 상태를 관리하는 강력한 도구입니다. 사용자 지정 기능을 추가할 수 있는 여러 미들웨어를 제공합니다. 그 중 가장 일반적인 것 중 하나가 Redux Thunk입니다.
Redux Thunk 소개
Thunk의 구현에 대해 자세히 알아보기 전에 효과적으로 사용할 수 있도록 정보를 수집해봅시다.
Thunk란 무엇인가요?
일반 프로그래밍에서 “Thunk”는 단순히 함수를 지연시키고 실행을 연기하는 데 사용되는 함수입니다. 이는 특정 조건이 충족될 때까지 작업을 연기하는 함수로 볼 수 있습니다.
Redux에서 Thunk는 Redux Thunk 미들웨어와 함께 사용되는 특정 함수입니다. Redux Thunk는 React 앱 내에서 비동기 작업을 수행할 수 있도록 설계되었습니다. 앞에서 언급했듯이 Reducer는 동기 코드를 실행하도록 작성되어 있습니다. 이는 액션이 디스패치되면 리듀서가 즉시 상태를 업데이트한다는 것을 의미합니다.
Redux Thunk as Middleware
Redux Thunk는 미들웨어로 작동합니다. 이를 사용하면 일반 액션 객체 대신 함수(청크)를 반환하는 액션 생성자를 작성할 수 있습니다. 이러한 함수에는 비동기 논리를 포함할 수 있습니다. 청크를 발송하면 Thunk 미들웨어가 이를 가로채고 함수를 실행합니다.
thunk
내에서 비동기 작업(예: API 호출)을 수행한 다음 작업이 완료되면 Redux 스토어를 업데이트하기 위해 일반 액션을 발송할 수 있습니다.
참고: Redux Thunk는 비동기 및 동기 작업 모두를 허용하지만 주요 목적은 비동기 액션을 용이하게 하는 것입니다. 동기 작업을 발송하는 것을 방해하지 않으며, 비동기 작업을 처리하는 메커니즘을 제공할 뿐입니다.
이제 React 미들웨어를 Redux Thunk를 구현하여 살펴보겠습니다.
Redux Thunk 구현 단계별 가이드
Redux 미들웨어를 구현하는 단계는 다음과 같습니다:
단계 1: Thunk로 Redux 설정React 애플리케이션을 생성하고 종속성을 설치합니다.
npx create-react-app newApp
Redux Thunk를 설치하려면 다음 명령을 실행합니다.
npm install redux-thunk
단계 3: Thunk 미들웨어 활성화
Enable the Thunk middleware in the Redux store.
import { configureStore } from '@reduxjs/toolkit';
import thunk from 'redux-thunk';
import rootReducer from './reducers'; // Combine all reducers here
const store = configureStore({
reducer: rootReducer,
middleware: [thunk],
});
export default store;
참고: Redux Toolkit을 사용할 때는 thunk
를 명시적으로 설치할 필요가 없습니다.
단계 4: 비동기 함수 작성
덩크는 상태를 읽거나 액션을 디스패치하는 dispatch
및 getstate
인수를 받는 다른 함수를 반환합니다. 다음은 데이터를 가져오는 예시 코드입니다:
// 액션 유형
const START_FETCH = 'START_FETCH';
const FETCH_SUCCESS = 'FETCH_SUCCESS';
const FETCH_ERROR = 'FETCH_ERROR';
// 액션 생성자
const startFetch = () => ({ type: START_FETCH });
const fetchSuccess = (data) => ({ type: FETCH_SUCCESS, payload: data });
const fetchError = (error) => ({ type: FETCH_ERROR, payload: error });
// 덩크 액션
export const fetchData = () => {
return async (dispatch, getState) => {
dispatch(startFetch()); // Notify that the fetch has started
try {
const response = await fetch('https://jsonplaceholder.typicode.com/posts');
if (!response.ok) {
throw new Error('Failed to fetch data');
}
const data = await response.json();
dispatch(fetchSuccess(data)); // Send the fetched data to the store
} catch (error) {
dispatch(fetchError(error.message)); // Handle any errors
}
};
};
단계 5: 리듀서에서 디스패치된 액션 처리
리듀서를 업데이트하여 디스패치된 액션을 처리하십시오.
const initialState = {
data: [],
isLoading: false,
error: null,
};
export const dataReducer = (state = initialState, action) => {
switch (action.type) {
case START_FETCH:
return { ...state, isLoading: true, error: null };
case FETCH_SUCCESS:
return { ...state, isLoading: false, data: action.payload };
case FETCH_ERROR:
return { ...state, isLoading: false, error: action.payload };
default:
return state;
}
};
단계 6: 컴포넌트에서 덩크 디스패치
useDispatch
훅을 사용하여 React 프로젝트에서 덩크를 디스패치합니다.
import React, { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { fetchData } from './actions';
const DataComponent = () => {
const dispatch = useDispatch();
const { data, isLoading, error } = useSelector((state) => state.data);
useEffect(() => {
dispatch(fetchData()); // Trigger the thunk to fetch data
}, [dispatch]);
if (isLoading) return <p>Loading...</p>;
if (error) return <p>Error: {error}</p>;
return (
<ul>
{data.map((item) => (
<li key={item.id}>{item.title}</li>
))}
</ul>
);
};
export default DataComponent;
createAsyncThunk 사용
Redux Toolkit에는 비동기 함수에 대한 고수준 로직을 정의하고 디스패치하며 오류를 신속히 처리하는 내장 API가 포함되어 있습니다. 비동기 함수의 구체적인 사용 사례에 대한 추상화를 제공하기 때문에, createAsyncThunk
는 덩크의 모든 사용 사례에 적용되지는 않음을 유의하십시오.
다음은 createAsyncThunk
의 예시 구현입니다:
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
export const dataFetch = createAsyncThunk('data/fetchData', async () => {
const response = await fetch('https://api.example.com/data');
return response.json();
});
const dataSlice = createSlice({
name: 'data',
initial_State: { data: [], loading: false, error: null },
extraReducers: (builder) => {
builder
.addCase(dataFetch.pending, (state) => {
state.loading = true;
state.error = null;
})
.addCase(dataFetch.fulfilled, (state, action) => {
state.loading = false;
state.data = action.payload;
})
.addCase(dataFetch.rejected, (state, action) => {
state.loading = false;
state.error = action.error.message;
});
},
});
export default dataSlice.reducer;
이제 dataFetch
덩크를 디스패치하려면 다음 코드를 사용하십시오:
dispatch(dataFetch ());
React 미들웨어 사용 사례 – Redux Thunk
덩크는 다음과 같은 다양한 목적으로 사용할 수 있습니다:
- 컴포넌트에서 복잡한 로직을 추상화합니다.
- 비동기 요청 및 로직 수행.
- 여러 액션을 시리즈로 디스패치하기 위한 함수 작성.
리액트 미들웨어가 다른 상태 관리 라이브러리에서의 활용
리덕스만이 미들웨어를 활용하는 리액트 라이브러리는 아닙니다. 다른 상태 관리 라이브러리에서도 미들웨어를 찾을 수 있지만, 이러한 라이브러리에서의 이 개념 구현은 리덕스와는 다릅니다.
MobX
MobX에는 리덕스와 같은 전통적인 미들웨어가 없습니다. 대신, 인터셉터, 옵저버, 반응 등의 메커니즘을 통해 비슷한 기능을 제공합니다. 이러한 메커니즘을 사용하여 MobX 상태의 변경 사항을 관찰하고 이에 반응할 수 있습니다. 이를 통해 MobX는 리덕스에서 보통 미들웨어가 처리하는 부수 효과, 로깅 및 기타 작업을 처리할 수 있는 방법을 제공합니다.
Recoil
Recoil은 리덕스와는 다르게 미들웨어를 지원하지 않습니다. 왜냐하면 필요하지 않기 때문입니다. 특정 함수를 사용하여 상태 조각(원자)을 직접 업데이트할 수 있습니다. 리듀서에 액션을 디스패치하고 미들웨어로 가로채는 것이 없습니다. 비동기 작업을 처리하기 위해, Atom이나 다른 Selector에 따라 파생된 상태를 사용합니다.
Zustand
간단한 API로 상태를 관리하고, 리덕스와 마찬가지로 로깅 및 상태 저장을 위한 네이티브 미들웨어를 지원합니다.
XState
XState는 onTransition
, actions
, 및 services
와 같은 훅을 사용하여 미들웨어와 유사한 동작을 지원합니다. 이러한 훅은 상태 전이를 가로채고 수정하는 데 도움을 줍니다.
결론
미들웨어는 웹 애플리케이션의 다양한 구성 요소를 연결하고 결합하여 더 나은 데이터 흐름과 처리를 위한 다리 역할을 합니다. 그들은 백엔드에서 널리 사용되어 왔지만 이제 프론트엔드에서도 사용 사례를 찾았습니다.
React에서 미들웨어를 구현하는 다양한 방법이 있습니다. 보통 Redux, MobX와 같은 상태 관리 라이브러리에 연결됩니다. 가장 일반적으로 사용되는 React 미들웨어인 Thunk는 Redux 라이브러리에 포함되어 있습니다. Thunk는 지연된 작업을 수행하는 코드 블록입니다.
본 글에서는 React의 미들웨어, Redux 라이브러리, 그리고 Redux Thunk를 탐색했습니다. 또한 데이터를 가져오고 액션을 디스패치하기 위해 Redux Thunk 미들웨어를 구현하는 단계를 다루었습니다.
Source:
https://dzone.com/articles/demystifying-react-middleware-bridging-apis-and-co