본문 바로가기
  • 삽질하는 자의 블로그
메인-프로젝트/MERN - 다이어리 프로젝트

8.[클라이언트] - Redux-Toolkit ( Typescript )을 이용해, DB의 값 가져오기 (Thunk 액션 생성자 )

by 이게뭐당가 2023. 2. 21.

DB 에 있는 값을, Store 로 직접 가져오는 Thunk 액션 생성자를 사용해본다.

 

 

준비물

typescript
react-redux
redux-toolkit
데이터베이스 서버
서버

 


1. Slice 의 생성

 

store 폴더 안에 slice 를 생성한다.

< store / user-diary-slice.ts >

    import { createSlice, PayloadAction } from "@reduxjs/toolkit";

    export interface TypeUserDiary {		// 타입 지정
      _id: string; // mongodb 자동
      userEmail: string;
      diaryTitle: string;
      diaryContent: string;
      feeling: number;
      date: string;
    }

    const initialState: { userDiaryData: TypeUserDiary[] } = { userDiaryData: [] };	// 초기값

    const userDiarySlice = createSlice({		// 슬라이스 생성
      name: "userDiary",
      initialState,
      reducers: {
        putUserDiary(state, action: PayloadAction<TypeUserDiary[]>) {	// reducer 설정
          state.userDiaryData = action.payload;
        },
      },
    });

    export const userDiaryAction = userDiarySlice.actions;

    export default userDiarySlice.reducer;

 

주의사항

 

1. payload 타입의 지정

 

 


 

2. store 의 생성

 

store 폴더의 index.ts 안에 store 를 생성한다.

< store / index.ts >

    import { configureStore } from "@reduxjs/toolkit";

    import userDiarySlice from "./user-diary-slice";

    export const store = configureStore({
      reducer: { userDiary: userDiarySlice },
    });

    export type RootState = ReturnType<typeof store.getState>;	// select 하기위한 RootState 타입
    export type AppDispatch = typeof store.dispatch;		// Dispatch 를 위한 AppDispatch 타입

주의사항

 

1. Root State 의 타입을 지정하고 export 

2. AppDispatch 의 타입을 지정하고 export


 

3. store 의 등록

 

메인 파일에 react-redux 를 통해, store 를 등록, 제공한다.

< index.tsx >

		...
    import { Provider } from "react-redux";
    import { store } from "./store/index";

    const root = ReactDOM.createRoot(
      document.getElementById("root") as HTMLElement
    );
    root.render(
      <React.StrictMode>
        <Provider store={store}>		// store 등록
          <BrowserRouter>
            <Layout>
              <App />
            </Layout>
          </BrowserRouter>
        </Provider>
      </React.StrictMode>
    );

 


 

4. action 의 생성

 

slice 안의 reducer 함수에는 순수함수만을 사용할 수 있다.

순수함수가 아닌 비동기함수(fetch) 를 사용하기 위해, 

비동기 함수를 처리할 action 을 따로 정의해 사용하도록 한다.

그것이 Thunk 액션 생성자이다.

 

store 폴더 안에 action 을 정의한다.

 

< store / user-diary-slice.ts >

    import { Dispatch } from "@reduxjs/toolkit";	// action 을 실행시키기 위한, Dispatch 의 타입을 가져온다.
    import { userDiaryAction } from "./user-diary-slice";// store 에 저장하기 위해(action 실행), slice 에서 저장한 action 가져온다.
    import { useDispatch } from "react-redux"; 		// useDispath 의 사전 생성
    import type { AppDispatch } from "./index"; 	//  action 생성자용 Dispatch 타입

    export const getRequest = (userEmail: string) => {	// 1. 일반함수 생성(파라미터는 자유)
      return async (dispatch: Dispatch) => {		// 2. 일반함수는 비동기함수를 반환한다.
        const getUserDiaryData = async () => {		// 3. 반환되는 함수 안에 실제 fetch할 함수를 생성
          const response = await fetch(
            `http://localhost:5000/api/diary/${userEmail}`
          );
          const responseData = await response.json();
          return responseData.data;
        };

        const userDiaryData = await getUserDiaryData();		// 4. fetch할 함수를 실행시키고
        dispatch(userDiaryAction.putUserDiary(userDiaryData));	// 5. dispatch를 진행하여, store 에 저장
      };
    };

    export const useAppDispatch: () => AppDispatch = useDispatch;// 6. 컴포넌트에서 사용할 dispatch 타입 지정

주의사항

 

1. export 하는 함수는 "일반함수"이다. async 를 사용하는 실수를 조심하자.

2. 마치 useEffect 안에서, 비동기함수를 실행시키는 것 처럼

    일반함수에서 비동기함수를 정의하고, 실행시키고, store 에 넣는 형태를 가진 일반함수인 것이다.

     그리고 정의된 일반함수(정의한 최상단 일반함수 - getRequest) 를 컴포넌트에서 실행시키는 것 뿐이다.

 

3. AppDispatch 의 타입을 지정하고 export 할것.

 


5. 컴포넌트 내에서 액션 생성자의 사용

 

사용법은 단순하다.

1. action 생성자를 만들때, 사전 정의한 useAppDispatch 를 통해, dispatch 하고

2. react-redux 의 dispatch 처럼, dispatch( ... ) 처럼 사용하면된다.

 

< App.tsx > 

    import { useEffect } from "react";
    import { useAppDispatch, getRequest as getRequestForDiary } from "./store/user-diary-action";
    import { useSelector } from "react-redux";
    import { RootState } from "./store";

    let initial = true;

    function App() {
      const dummyuUserEmail = "mms@ms.com"; 	// 추후 OAuth 로 변경
      const dispatch = useAppDispatch();
      const userDiaryData = useSelector(		// 단순 확인용 ( 여기서 필요 없음 )
        (state: RootState) => state.userDiary.userDiaryData
      );

      useEffect(() => {
        if (initial) {
          initial = false;
          return;
        }
        dispatch(getRequestForDiary(dummyuUserEmail));	// 유저 EMAIL 을 인수로 
      }, []);

      return (
        <div className="App">
        	...

댓글