#1. 비동기 처리
1. Redux에서 비동기 처리하기
- Redux는 기본적으로 동기 처리만 지원하기 때문에 비동기 처리를 하기 위해서는 확장 패키지가 필요하다.
- ex) Redux-Thunk, Redux-saga 등의 미들웨어
1) slice 설정
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import axios from 'axios';
// TODO: 비동기 처리 함수 구현
// payload는 이 함수를 호출할 때 전달되는 파라미터
export const 액션함수 = createAsyncThunk('액션함수별칭', async (payload, {rejectWithValue}) => {
let result = null;
try {
result = await axios.get(url 및 파미터);
} catch(error) {
// rejectWithValue는 에러 발생시 사용
result = rejectWithValue(error.response);
}
return result;
});
// TODO: Slice 정의 (Action함수 + Reducer의 개념)
const slice이름 = createSlice({
name: 'department',
initialState: {
// 상태값 구조 정의 (자유롭게 구성 가능)
data: null, // Ajax 처리를 통해 수신된 데이터
loading: false, // 로딩 여부
error: null, // 에러 정보
},
// 내부 action 및 동기 action시 (ajax 처리시에는 사용하지 않음)
reducers: {},
// 외부 action 및 비동기 action (ajax 처리시 사용)
// 액션함수에서 파생된 3개의 함수 -> 1세트
extraReducers: {
// Ajax 요청 준비
[액션함수.pending]: (state, {payload}) => { // pending -> 로딩
// state 값을 적절히 수정하여 리턴한다.
return {...state, loading: true}
},
// Ajax 요청 성공
[액션함수.fulfilled]: (state, {payload}) => { // fulfilled -> ajax완료
return {
data: payload?.data,
loading: false,
error: null,
}
},
// Ajax 요청 실패
[액션함수.rejected]: (state, {payload}) => { // rejected -> error
return {
data: payload?.data,
loading: false,
error: {
code: payload?.staus ? payload.staus : 500,
message: payload?.stausText ? payload.stausText : 'Server Error'
}
}
}
}
});
// 리듀서 객체 내보내기
export default slice이름.reducer;
- createAsyncThunk 함수 호출시 사용된 payload는 이 함수를 호출할 때 전달되는 파라미터이다.
- rejectWithValue 함수는 에러 발생시 에러 데이터를 전달하면 extraReducer의 rejected 함수가 호출된다.
- extraReducer 에는 사용할 액션함수에서 파생된 3개의 함수가 있는데 이 함수들은 1세트로 봐야한다.
- [액션함수.pending]: Ajax 요청 준비 (로딩)
- [액션함수.fulfilled]: Ajax 요청 성공 (Ajax 완료)
- [액션함수.rejected] : Ajax 요청 실패 (에러)
2) store 설정
- 보통은 slice를 먼저 작성 후 store를 작성한다. (기본틀은 먼저 작성해도 무관!)
import { configureStore } from '@reduxjs/toolkit';
import slice이름 from '...';
const store = configureStore({
reducer: {
// 개발자가 직접 작성한 reducer들이 명시되어야 한다.
slice별칭: slice이름,
},
// 미들웨어를 사용하지 않을 경우 이 라인 생략 가능 (redux-thunk 사용시 필수)
middleware: (getDefaultMiddleware) => getDefaultMiddleware({serializableCheck: false}),
// redux-devtools-extention을 사용하지 않을 경우 false 혹은 이 라인을 명시 안함
devTools: true,
});
export default store;
- 미들웨어 사용 설정에서 동기 처리 체크(serializableCheck)를 사용할지 안할지 설정한다.
- true는 사용, false는 사용안함 (또는 생략)
- redux-devtools-extention을 사용하지 않을 경우 false 또는 명시하지 않는다.
※ redux-devtools-extention 사용하기
- 리덕스의 상태를 크롬브라우저 개발도구에 설치된 확장 기능과 연동할 수 있게 해주는 미들웨어이다.
- redux-logger와 기능이 비슷하기 때문에 취향에 따라 사용하면 된다.
- 리덕스가 관리하는 상태값을 자동으로 로그에 표시해준다.
- 패키지 설치
yarn add redux-devtools-extension
- 크롬 웹스토어 설치
- 패키지 설치와 크롬 웹스토어 설치가 끝나면 개발자도구에서 사용할 수 있다.
- devTools: false 로 설정하면 아래 이미지와 같이 찾을 수 없다는 메세지가 나온다.
3) 필요한 이벤트 핸들러 안에서 액션함수 디스패치
- slice에서 정의한 액션함수의 action.payload 파라미터로 전달된다.
- 다수의 파라미터가 필요한 경우 JSON 객체로 묶어서 전달한다.
dispatch(액션함수1(파라미터));
dispatch(액션함수2(파라미터));
2. 실습
※ 데이터 연동은 Json-server 사용
- index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
// 리덕스 구성을 위한 참조
import { Provider } from 'react-redux';
import store from './store';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);
- App.jsx
import React from 'react';
import Department from './pages/Department';
function App() {
return (
<div>
<h1>비동기 처리</h1>
<Department />
</div>
);
}
export default App;
- DepartmentSlice.jsx
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import axios from 'axios';
// TODO: 비동기 처리 함수 구현
export const getList = createAsyncThunk('department/getList', async (payload, {rejectWithValue}) => {
let result = null;
try {
result = await axios.get('http://localhost:3001/department');
} catch(error) {
// rejectWithValue -> 에러 발생시 사용
result = rejectWithValue(error.response);
}
return result;
});
// TODO: Slice 정의 (Action함수 + Reducer의 개념)
const departmentSlice = createSlice({
name: 'department',
initialState: {
data: null, // Ajax 처리를 통해 수신된 데이터
loading: false, // 로딩 여부
error: null, // 에러 정보
},
// 내부 action 및 동기 action을 할때는? (ajax와 상관이 없을 때)
reducers: {},
// 외부 action 및 비동기 action을 할때는? (ajax용)
// getList에서 파생된 3개의 함수 -> 1세트
extraReducers: {
[getList.pending]: (state, {payload}) => { // pending -> 로딩
return {...state, loading: true}
},
[getList.fulfilled]: (state, {payload}) => { // fulfilled -> ajax완료
return {
data: payload?.data,
loading: false,
error: null,
}
},
[getList.rejected]: (state, {payload}) => { // rejected -> error
return {
data: payload?.data,
loading: false,
error: {
code: payload?.staus ? payload.staus : 500,
message: payload?.stausText ? payload.stausText : 'Server Error'
}
}
}
}
});
export default departmentSlice.reducer;
- store.jsx
import { configureStore } from '@reduxjs/toolkit';
import departmentSlice from './slices/DepartmentSlice';
const store = configureStore({
reducer: {
// 개발자가 직접 작성한 reducer들이 명시되어야 한다.
department: departmentSlice,
},
// 미들웨어를 사용하지 않을 경우 이 라인 생략 가능 (redux-thunk 사용시 필수)
middleware: (getDefaultMiddleware) => getDefaultMiddleware({serializableCheck: false}),
// redux-devtools-extention을 사용하지 않을 경우 false 혹은 이 라인을 명시 안함
devTools: true,
});
export default store;
- Department.jsx
import React, { memo, useEffect } from 'react';
// 상태값을 로드하기 위한 hook과 action 함수를 dispatch할 hook 참조
import { useSelector, useDispatch } from 'react-redux';
// Slice에 정의된 액션함수들 참조
import { getList } from '../slices/DepartmentSlice';
const Department = () => {
// hook을 통해 slice가 관리하는 상태값 가져오기
const {data, loading, error} = useSelector((state) => state.department);
// dispatch 함수 생성
const dispatch = useDispatch();
// 컴포넌트가 마운트 되면 데이터 조회를 위한 액션함수를 디스패치함
useEffect(() => {
dispatch(getList())
}, [dispatch]);
return (
<div>
{error ? (
<h1>{error.code} Error.</h1>
) : (
<table border='1'>
<thead>
<tr>
<th>id</th>
<th>dname</th>
<th>loc</th>
</tr>
</thead>
<tbody>
{data && data.map(({id, dname, loc},i) => (
<tr key={id}>
<td>{id}</td>
<td>{dname}</td>
<td>{loc}</td>
</tr>
))}
</tbody>
</table>
)}
</div>
);
};
export default memo(Department);
※ 출력결과
'국비수업 > React' 카테고리의 다른 글
[React/Redux] Redux (0) | 2022.05.20 |
---|---|
[React] Axios-hooks (0) | 2022.05.17 |
[React] Axios 사용하기 (0) | 2022.05.15 |
[React] Hooks (0) | 2022.04.29 |
[React] CSS 사용하기 (0) | 2022.04.26 |