반응형
React + Redux 상테에서 Redux-Saga 설정
1. redux-saga 모듈 설치
npm install redux-saga
npm install axios // saga 로직에서 쓰임
2. actions, reducers, store 폴더에 해당 파일을 생성한다.
store/actions/actionTypes.ts 수정
export const INCREASE = 'counter/INCREASE'
export const DECREASE = 'counter/DECREASE'
// search
export const SEARCH = 'SEARCH';
export const SEARCH_SUCCESS = 'SEARCH_SUCCESS';
export const SEARCH_FAIL = 'SEARCH_FAIL';
store/actions/search.ts 추가
import {SEARCH , SEARCH_SUCCESS, SEARCH_FAIL } from './actionTypes';
export const search = (payload) => {
return {
type: SEARCH,
payload: payload
}
}
export const searchSuccess = (data) => {
return {
type: SEARCH_SUCCESS,
data: data
}
}
export const searchFail = (error) => {
return {
type: SEARCH_FAIL,
error: error
}
}
store/reducers/search.ts 추가
import * as actions from 'store/actions/actionTypes'
const initialState = {
data: [],
payload: {},
error: ''
}
export default (state=initialState, action) => {
switch(action.type){
case actions.SEARCH:
console.log(1, {
...state,
payload: action.payload
})
return {
...state,
payload: action.payload
}
case actions.SEARCH_SUCCESS:
console.log(2, {
...state,
data: action.data
})
return {
...state,
data: action.data
}
case actions.SEARCH_FAIL:
console.log(3, {
...state,
error: action.error
})
return {
...state,
error: action.error
}
default:
return state;
}
}
store/reducers/index.ts 수정
import { combineReducers } from "redux";
import counter from "./counter";
import search from "./search";
const rootReducer = combineReducers({
counter: counter,
search: search
})
export default rootReducer
export type RootState = ReturnType<typeof rootReducer>
store/sagas/SearchSaga.ts 추가
import { call, put, takeEvery } from "redux-saga/effects";
import {SEARCH} from 'store/actions/actionTypes'
import * as actions from "store/actions/search";
import axios from "axios";
function searchAPI(data) {
return axios.get(`https://api.tvmaze.com/search/shows?q=superman`)
}
function* fetchSearchSaga(action) {
try {
const { data } = yield call(searchAPI, action.data)
yield put(actions.searchSuccess(data));
} catch (error) {
yield put(actions.searchFail('error'));
}
}
/**
* SEARCH DISPATH EVENT WATCH
* 이벤트기 감지되었을때 동작한다.
*/
export default function* watchSearch() {
yield takeEvery(SEARCH, fetchSearchSaga);
}
store/sagas/index.ts 추가
import { all, call } from 'redux-saga/effects';
import watchSearch from './SearchSaga'
export default function* rootSaga() {
yield all([
call(watchSearch)
])
}
store/index.ts 파일을 수정합니다.
import { createStore, applyMiddleware, Middleware, StoreEnhancer } from "redux"
import rootReducer from "./reducers";
import { MakeStore, createWrapper } from "next-redux-wrapper";
import createSagaMiddleware from "redux-saga";
import rootSaga from "./sagas";
const bindMiddleware = (middleware: Middleware[]): StoreEnhancer => {
if (process.env.NODE_ENV !== 'production') {
const { composeWithDevTools } = require('redux-devtools-extension');
return composeWithDevTools(applyMiddleware(...middleware));
}
return applyMiddleware(...middleware);
}
const makeStore: MakeStore<{}> = () => {
const sagaMiddleware = createSagaMiddleware();
const middlewares = [sagaMiddleware];
const store = createStore(rootReducer, {}, bindMiddleware([...middlewares]));
sagaMiddleware.run(rootSaga);
return store
}
export const wrapper = createWrapper<{}>(makeStore, { debug: true });
3. Redux-Saga 정상동작확인
npm run dev
실행 후 웹페이지에 접속했을때 VScode 터미널에 아래 내용이 나오면 정상적으로 설정된것입니다.
4. Redux-Saga 테스트
pages/index.tsx 파일을 수정합니다.
import Head from 'next/head'
import { useCallback } from 'react'
import { useDispatch, useSelector } from 'react-redux';
import {RootState} from 'store/reducers'
import { countUp, countDown } from 'store/actions/count';
import { search } from 'store/actions/search';
import styles from 'styles/Home.module.css'
import styled from 'styled-components';
const NavbarWrapper = styled.div`
background-color: #ededed;
padding: ${({ theme }) => theme.colors.black}
`
export default function Home() {
const dispatch = useDispatch();
const {value} = useSelector((state: RootState) => state.counter)
const searchData = useSelector((state: RootState) => state.search)
const upEvent = useCallback(() => {
dispatch(countUp())
}, [])
const downEvent = useCallback(() => {
dispatch(countDown())
}, [])
const searchEvent = useCallback(() => {
dispatch(search({test: 'test1'}))
//'superman'
}, [])
return (
<NavbarWrapper>
<Head>
<title>Create Next App</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<div className={styles.home}>
<div className={styles['counter__text']}>{value}</div>
<div className={styles['button__area']}>
<button onClick={upEvent}>Up</button>
<button onClick={downEvent}>Down</button>
</div>
<button onClick={searchEvent}>Search</button>
</div>
{searchData.data && (
<div>
{searchData.data.map((show, index) => (
<div key={index}>
<a href={show.url}>{show.name}</a>
<div>점수 : {show.score}</div>
<div>타입 : {show.type}</div>
<div>언어 : {show.language}</div>
</div>
))}
</div>
)}
</NavbarWrapper>
)
}
전체적인 코드는 제 Github 공유드리겠습니다. github.com/jkkim09/nextjs-study
아래 링크들을 하나씩 따라시면 Redux-Saga 설정까지 해보실 수 있습니다.
반응형
'Tech > React' 카테고리의 다른 글
Next + Typscript + Redux 설정 (0) | 2021.03.11 |
---|---|
Next + Typescript 설정 (0) | 2021.03.11 |
Next.js(react) 프로젝트 시작 (0) | 2021.03.11 |
댓글