Redux-middleware
리덕스를 사용하는 이유 중에 하나는 미들웨어이다.
리덕스 미들웨어를 사용하면 액션을 디스패치하고 그 액션이 리듀서에 가기 전에 추가적인 작업을 더 해줄 수 있다.
그래서 보통 비동기 방식으로 사용할 때 미들웨어를 많이 사용한다고 한다.
(서버에서 액션을 받아오면 리듀서에 가기 전에 비동기로 데이터를 받아서 보내줘야 하기 때문).
리덕스 미들웨어는 개인이 필요한 용도로 만들어서 쓸 수도 있지만
보통은 만들어진 미들웨어를 받아와서 사용한다.
redux-promise-middleware 등이 있다.
이번 포스팅에서는 리덕스 미들웨어가 어떤 건지 파악만 하기 때문에
직접 미들웨어를 만들어보고 대강의 구조를 파악해 보겠다.
1. 리듀서에 가기 전 추가적인작업
dispatch({ type:"add_todo" })
리덕스 미들웨어를 사용하면 액션이 디스패치된 다음,
리듀서에서 해당 액션을 받아서 업데이트하기 전에
추가적인 작업을 할 수 있음.
서버에 있는 값을 받아서 업데이트해 줄 때 주로 사용.(비동기)
간단한 리덕스 모듈을 만들고 미들웨어를 만들어서 적용해 보겠다.
1. 리덕스 모듈 만들기
액션타입, 액션생성함수 리듀서
modules/counter.js
//액션타입
const INCREASE = 'counter/INCREASE';
const DECREASE = 'counter/DECREASE';
//액션생성함수 --> 액션을 리턴
export const increase = ()=>({type:INCREASE})
export const decrease = ()=>({type:DECREASE})
//초기값
const initialState = 0
//리듀서
export default function counter(state=initialState,action){
switch(action.type){
case INCREASE:
return state+1;
case DECREASE:
return state-1;
default:
return state;
}
}
2. 루트 리듀서 만들기
모듈이 여러 개일 때는 리듀서가 여러 개이기 때문에 리듀서들을 하나로 합쳐서 store를 만들 때 사용한다.
modules/index.js
import { combineReducers } from "redux";
import counter from "./counter";
const rootReducer = combineReducers({ counter })
export default rootReducer
3. 스토어 만들기 , 전역에 스토어 사용하기
만들어진 rootreducer를 이용해서 스토어를 만들고 스토어를 사용할 수 있게 하위컴포넌트들을 묶어준다.
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { legacy_createStore as createStore } from 'redux';
import rootReducer from './modules';
import { Provider } from 'react-redux';
//스토어 만들기.
const store = createStore(rootReducer)
console.log(store.getState()) //상태값 조회
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
스토어를 만들었으니 상태를 관리할 준비는 다 끝났고 이제
counter의 상태를 이용해서 간단한 화면을 구현해 보자
화면적으로 보이는 프레젠테이셔널컴포넌트를 먼저 만들고
값을 전달해 줄 컨테이너컴포넌트를 만들어주겠다.
component/Counter.js
import React from 'react';
const Counter = ({number,onIncrease,onDecrease}) => {
return (
<div>
<h2>{number}</h2>
<button onClick={onIncrease}>+</button>
<button onClick={onDecrease}>-</button>
</div>
);
};
export default Counter;
화면에 보여줄 현재 숫자를 number로 받아오고 버튼을 클릭했을 때
상태값을 + , - 해줄 함수로 onIncrease와 onDecrease를 받아왔다.
이제 이 값들을 보내줄 컨테이너 컴포넌트를 보자.
containers/CounterContainer.js
import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import Counter from '../components/Counter';
import { decrease, increase } from '../modules/counter';
const CounterContainer = () => {
const number = useSelector(state=>state.counter)
const dispatch = useDispatch()
const onIncrease=()=>{
dispatch(increase()) //export const increase = ()=>({type:INCREASE})
}
const onDecrease=()=>{
dispatch(decrease()) //export const decrease = ()=>({type:DECREASE})
}
return (
<div>
<Counter number={number} onIncrease={onIncrease} onDecrease={onDecrease}/>
</div>
);
};
export default CounterContainer;
useSelector로 counter의 상태값을 number로 받아서 Counter컴포넌트에 props로 보내준다.
useDispatch로 dispatch함수를 받아와서 디스패치를 실행하는 함수를 만들었다 onIncrease ,onDecrease
dispatch에 액션객체로는 액션생성 함수를 넣어줬다.
이렇게 만들어준 함수를 Counter컴포넌트에 props로 넘겨준다.
이제 이 컨테이너 컴포넌트를 app.js에 넣어서 렌더링만 해주면 된다.
이제 여기에 미들웨어를 하나 만들어서 값이 리듀서로 가기 전에 작업을 할 수 있게 해 주겠다.
*리덕스 미들웨어
미들웨어는 함수를 연달아서 두 번 리턴하는 함수.
const middleware = store => next => action =>{
//하고싶은작업..
}
function middleware(store){
return function(next){
return function(action){
//하고싶은작업..
}
}
}
위와 같은 구조가 미들웨어의 구조이다 store는 파라미터로 들어가고 함수를 두번 리턴해준다.
각 함수에서 받아오는 파라미터
-store 리덕스 스토어 store dispatch( ) / getState( ) / subscribe( ) 내장함수 들어있음
-next 액션을 다음 미들웨어에 전달하는 함수
ex) next(action)
-action 은 현재 처리하고 있는 액션객체
-next(action)을 해주지 않으면 action이 reducer나 다음 미들웨어로 넘어가지 않아서 에러가 생긴다.
middlewares/myLogger.js
const myLogger = store => next =>action=>{
//액션 출력하기
console.log(action)
//next는 다음미들웨어 또는 리듀서 에게 액션을 전달.
const result = next(action); //다음 미들웨어가 없어서 리듀서가호출되고 상태값이 변함
// 업데이트 이후의 상태를 출력
console.log(store.getState());
//여기에서 반환하는 result값은 dispatch(action)의 결과물.
return result
}
export default myLogger;
지금 보내주는 액션을 콘솔에 출력해 주고 action을 다음미들웨어로 넘겨준다.
미들웨어로 action이 넘어간 다음 바뀐 상태값을 출력해 준다.
이제 만들어진 이 미들웨어를 사용해 보자
store를 만들 때 미들웨어를 같이 넣어주면 된다.
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { applyMiddleware , legacy_createStore as createStore } from "redux";
import { Provider } from "react-redux";
import App from "./App";
import rootReducer from "./modules";
import myLogger from './middlewares/myLogger';
const rootElement = document.getElementById("root");
const root = createRoot(rootElement);
const store = createStore(rootReducer,applyMiddleware(myLogger));
console.log(store.getState());
root.render(
<StrictMode>
<Provider store={store}>
<App />
</Provider>
</StrictMode>
);
applyMiddleware를 import 해서 createstore안에 넣어주고 사용할 미들웨어를 파라미터로 넣어준다.
콘솔을 확인해 보면 어떤 액션이 들어가고 상태값이 어떻게 변하는지 미들웨어에서 출력을 해준다
이렇게 리듀서로 들어가는 자료들을 중간에서 받아서 출력해 줄 수도 있고 변경해서 다시 보내줄 수도 있는 게 미들웨어의 역할이다.
만들어진 미들웨어 써보기
redux-logger
npm install --save react-redux
redux-logger는 만들어져 있는 미들웨어이며 이전상태값과 액션 다음상태값을 출력해준다.
원래 저기에 이전상태값이랑 action객체 다음 상태값이 다 떠야되는데 왜 안뜨는건지...
원래는 이렇게 상태값과 액션객체가 뜬다.
피드백
사실 미들웨어는 저번주 금요일에 배웠던 개념인데 이해가 너무안되서 정리를 좀더 해보고 오늘 학원에서도 다시해보고 thunk를 배우면서 어느정도 개념에 대해서 받아들여진것같다. 역시 코딩은 안되면 일단 반복하면 되는구나..
다음 포스팅은 thunk에 대해서 할것같은데 이것도 아직 제대로 알아먹은건아니라서 두루뭉술하게 될지도. 일단 인강이나 이런거 찾아보고 내 뇌속의 개념을 조금더 보충해서 알아보기쉬운 포스팅을 쓸려고 하고있다. 그냥 코드만 따라하는건 아무나 하는거고 코드를 보고 이해할수있는게 중요한것같다. 이제 포트폴리오 준비도 해야되고 정신도 없지만 . 배우는 개념들은 모두 놓치지않고 이해하고싶다.
'프론트엔드 정복기 > 리액트' 카테고리의 다른 글
리액트 쇼핑몰만들기(프로젝트 세팅) (1) | 2024.11.10 |
---|---|
[React] react-redux part2 (todos추가) (0) | 2023.01.27 |
[React] 24 상태관리 3 (react-redux) (1) | 2023.01.27 |
[React]23 쇼핑몰 프로젝트 0.2ver (이미지 파일 보내기 , 상품 추가하기,MulterAPI) (0) | 2023.01.24 |
[React]22 리액트쇼핑몰만들기ver0.1 (서버에서 상품정보받아오기) (0) | 2023.01.20 |