redux-thunk middleware를 이용해 개념을 다잡고 실제 로그인 회원가입을 해보왔다.
redux-thunk는 리덕스에서 비동기 작업을 처리 할 때 가장 많이 사용하는 미들웨어입니다.
Redux Thunk는 dispatch를 지연시키는데 사용될 수 있으며 특정 조건이 충족되는 경우에만 dispatch할 수 있다. 내부 함수는 dispatch와 getState를 매개변수로 둔다.redux-thunk middleware
const thunkMiddleware = ({ dispatch, getState }) => (next) => (action) => { if (typeof action === "function") { // 비동기 처리 return action(dispatch, getState); } return next(action); // 동기처리 };
실제 redux-thunk middleware에 코드이다.
사용해보기(로그인/회원가입)
npm install redux npm install react-redux npm install redux-thunk npm install redux-devtools-extension
위의 명령어를 순서대로 install 한다.
//store.js import { legacy_createStore as createStore, applyMiddleware, compose, } from "redux"; import { reducer } from "./Reducer/Reducer"; import thunk from "redux-thunk"; import { composeWithDevTools } from "redux-devtools-extension"; const initialState = { users: { data: {}, }, posts: [{ title: "", content: "" }], }; const enhancer = process.env.NODE_ENV === "production" ? compose(applyMiddleware(thunk)) : composeWithDevTools(applyMiddleware(thunk)); export const store = createStore(reducer, initialState, enhancer);
위에서 부터 천천히 설명하자면 legacy_createStore as createStore 이 코드가 눈에 띄일텐데 redux-toolkit에 권장사용을 유도하기 위해서 createStore에 밑줄이 그어져 있을 수 있다. 그럴때 저렇게 불러오면 createStore를 쓸 수 있다. 그리고 redux에서 필요한 걸 불러오고 마찬가지 reducer 컴포넌트 redux-thunk, redux-devtools-extension 에서 불러오고 enhancer로 묶어 store를 만들어준다.(redux-devtool 블로그 글을 보면 enhancer에 이해가 빠를 것 이다.)
// index.js import React from "react"; import ReactDOM from "react-dom/client"; import App from "./App"; import { store } from "./store"; import { Provider } from "react-redux"; const root = ReactDOM.createRoot(document.getElementById("root")); root.render( <React.StrictMode> <Provider store={store}> <App /> </Provider> </React.StrictMode> );
이제 react redux react-redux를 연결시켜 줄 것이다.
//action.js import axios from "axios"; export const signUp = (params) => async (dispatch, getState) => { const response = await axios.post( "http://localhost:8080/users/create", params ); console.log(getState()); dispatch({ type: "SIGNUP", payload: response }); }; export const signIn = (params) => async (dispatch, getState) => { const response = await axios.post( "http://localhost:8080/users/login", params ); console.log(getState()); dispatch({ type: "SIGNIN", payload: response }); };
redux-thunk middleware에 대한 action 함수이다. redux-thunk는 액션을 반환할 때 객체가 아니라 함수를 반환할 수 있게 해준다. 즉, 액션이 함수의 형태일 때 그 함수를 실행하고 내부 함수 (dispatch,getstate)를 매개변수로 실행하여 객체가 되었을 때 reducer로 dispatch 할 수 있게 해준다.
// 로그인&회원가입 import React, { useState } from "react"; import { useDispatch, useSelector } from "react-redux"; import { signIn, signUp } from "./Action/userAction"; function App() { const [email, setEmail] = useState(""); const [passWord, setPassWord] = useState(""); const dispatch = useDispatch(); const { data } = useSelector((state) => state.users); console.log(data); let body = { email: email, password: passWord }; const onClickSignUP = () => { dispatch(signUp(body)).then( (res) => console.log(res), alert("가입이 정상적으로 완료되었습니다") ); }; const onClickSignIn = () => { dispatch(signIn(body)); }; const onChangeEmail = (e) => { const { value } = e.target; setEmail(value); console.log(email); }; const onChangePassWord = (e) => { const { value } = e.target; setPassWord(value); console.log(passWord); }; return ( <> <input onChange={onChangeEmail} value={email} /> <input onChange={onChangePassWord} value={passWord} /> {!data ? ( <button onClick={onClickSignUP}>회원가입</button> ) : ( <button onClick={onClickSignIn}>로그인</button> )} {data && <div>{data.data.message}</div>} </> ); } export default App;
useDispatch useSelector로 dispatch 해주고 store에 있는 state를 가져와 return 해준다.
action type에 맞는 reducer를 만들어주어야 한다. 블로그에 따로 작성하지 않아 여기서 추가 설명해 주었다.회원가입
로그인
logger
redux를 쓰게 되면 console찍는데 불편함을 느낄 것이다. 그 불편함을
도우는 라이브러이다.npm i redux-logger
import { createLogger } from "redux-logger"; const logger = createLogger(); applymiddleware(thunk,logger)
Action async/await
export const signUp = async (params) => { const response = axios.post("http://localhost:8080/users/create", params); return { type: "SIGNUP", payload: response }; };
Uncaught Error: Actions must be plain objects. Use custom middleware for async actions.
async/await으로 불러보왔다. 다음과 같은 error가 떴다. response에 console찍었을때 객체인데 알고보니 async/await은 엄청큰 함수 이다. 함수가 끝나지 않은채 담긴 것이다. 즉, payload에 담겨져있는것은 함수이다.
그래서 thunk가 필요한 것이다. thunk는 함수를 반환시켜준다. 즉, 안에 내부함수를 실행하는걸 반환시켜주고 다시말하자면 그 내부함수가 다 실행되어 객체가 될 때 까지 지연시켜주기 때문에 비동기처리 async/await은 thunk middleware를 써주어야 한다.
틀린내용이 있으면 댓글로 남겨주시면 감사하겠습니다.