저번세션때 강사님이 기능하나하나를 만들어보면 좋다고 하셔서
한 사이트를 만든다기 보다는 하나의 기능을 구현해보는 방식으로
공부를 해나가려고 한다.
무언가를 만들어보기 앞서
개념부터 공부해 보자
미들웨어란 서로 다른 애플리케이션이 서로 통신하는 데 사용되는 소프트웨어이다.
리덕스는 동기적으로 동작한다.
시간을 딜레이시켜 동작한다던지, 외부 데이터를 요청하여, 응답화면을 보여준다던지 하는 비동기적인 요청이 필요할 경우 미들웨어를 사용한다.
비동기 작업을 처리할 때 사용하는 미들웨어는 오픈 소스 커뮤니티에 많이 공개되어있다.
대표적인 리덕스 미들웨어
redux-logger : 어떤 액션이 발생했는지 로그를 남겨주는 미들웨어
rudux-thunk,redux-saga : 비동기 작업을 처리할 수 있게 해주는 미들웨어
그중에서도 나는 가장 많이 알려진 thunk로 미들웨어를 사용해보았는데
다음주에는 다른 미들웨어들과도 장단점을 비교해 봐야겠다.
리덕스 창시자인 댄 아브라모프가 만든 가장 많이 사용되는 비동기 작업 미들웨어이다.
Thunk란 무슨뜻일까?
--> 무언가 일을 지연시키는 것을 의미
리덕스에서는 thunk가 어떻게 쓰이는 걸까.
우리가 알고 있는 기존의 리덕스에서 액션 생성 함수는 액션을 객체 형태로 반환해주는 함수이다. 하지만, 리덕스 썽크를 이용하면 액션 생성 함수는 객체가 아닌 함수를 반환할 수 있게 해줍니다. 즉, 객체가 아닌 함수를 반환해줌으로서 필요할 때 함수를 호출할 수 있는 썽크의 형태가 되는 것이다.
thunk에서는 extra reducer라는 리듀서가 등장한다.
간단히 말하자면 reducers는 내부에서 진행되는 action 및 동기 action을 넣는 공간이며
extraReducers는 반대로 외부/비동기 action을 넣는 공간으로 구분할 수 있다.
extraReducer는 slice.actions에서 생성되지 않은 action을 사용할 수 있게 해준다. 주로 다른 slice에 정의된 action이나 createAsyncThunk에서 사용된 비동기 action을 설정할 때 사용한다. 그리고 얘는 그냥 리듀서와 다르게 액션를 자동으로 생성하지 못한다 직접 만들어줘야 한다.
Action을 만드는 내장함수이다.
비동기 작업을 처리하는 액션을 만들어야 하는데
Pending
Fulfilled
Rejected
이상태별로 리듀서가 필요하기때문에 이를 만들어주는 역할을 한다.
이제 필요한 개념들을 익혔으니 직접 만들어보면서 연습을 해보자
먼저 생활코딩을 통해 연습을 하였다.
터미널에 설치를 해준다.
npm install axios redux-thunk
그다음 createSlice.js코드를 보자
import {createSlice, createAsyncThunk} from '@reduxjs/toolkit';
//1. 제일먼저할일 액션크리에이터 만들어주기
const asyncUpFetch = createAsyncThunk( //액션크리에이터
'counterSlice/asyncUpFetch', //액션타입(의미있게 적으면 된다.)
async () => {
const resp = await fetch('https://api.countapi.xyz/hit/opesaljkdfslkjfsadf.com/visits')
const data = await resp.json();
return data.value; //리턴한 값은 스토어의 스테이트를 바꾼다. -->액스트라 리듀서스를 만들어줙야겠져..? 이 data.value는 fullfilled됐을때 action.payload값으로 이동한다.
// }
// )
const counterSlice = createSlice({
name:'counterSlice',
initialState:{
value:0,
status:'Welcome'
},
reducers:{
up:(state, action)=>{
state.value = state.value + action.payload;
}
},
extraReducers: (builder) => { //비동기 작업이 시작됐을때
builder.addCase(asyncUpFetch.pending, (state,action)=>{ //pending일때 동작할 리듀서를 두번째 파라미터의 함수로 전달.
state.status = 'Loading';
})
builder.addCase(asyncUpFetch.fulfilled, (state,action)=>{ //비동기작업이 끝났을때 (데이터를 가져왔을대)
state.value = action.payload;
state.status = 'complete';
})
builder.addCase(asyncUpFetch.rejected, (state,action)=>{ //오류가 났을때
state.status = 'fail';
})
}
});
export default counterSlice;
export const {up, set} = counterSlice.actions;
export {asyncUp, asyncUpFetch}
생각보다 간단한거 같은데 혼자하라고 하면 도통 용기가 나질 않는다.
App.js코드를 보자.
import React from "react";
import {createStore} from 'redux';
import {Provider,useSelector,useDispatch} from 'react-redux';
import store from './store';
import {up} from './counterSlice';
import {asyncUpFetch} from './counterSlice'; //호출
function Counter(){
const dispatch = useDispatch();
const count = useSelector(state=>{
return state.counter.value;
});
const status = useSelector(state=>{
return state.counter.status;
});
return <div>
<button onClick={()=>{
dispatch(up(2));
}}>+</button>
{ <button onClick={()=>{
dispatch(asyncUpFetch()); //이렇게 코드 한줄로 비동기통신이 가능해진다.
}}>+ async fetch</button><br/> }
<div>{count} | {status}</div>
</div>
}
export default function App() {
return (
<Provider store={store}>
<div>
<Counter></Counter>
</div>
</Provider>
);
}
생활코딩 강의를 두번돌려보니
조금 감이 오는거 같기도 하고
아리까리 하다
독학으로 여기까지 왔듯이
이또한 내껄로 만들수 있으리.....
—————————
참고자료
https://velog.io/@hoyun7443/React-%EB%A6%AC%EB%8D%95%EC%8A%A4-%EB%AF%B8%EB%93%A4%EC%9B%A8%EC%96%B4%ED%8E%B8
생활코딩
https://www.youtube.com/watch?v=K-3sBc2pUJ4
————